2 * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
20 FILE_LICENCE ( GPL2_OR_LATER
);
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>
38 * IPv6 neighbour discovery protocol
42 static struct ipv6conf
* ipv6conf_demux ( struct net_device
*netdev
);
44 ipv6conf_rx_router_advertisement ( struct net_device
*netdev
,
45 struct in6_addr
*router
,
46 struct ndp_router_advertisement_header
*radv
,
50 * Transmit NDP packet with link-layer address option
52 * @v netdev Network device
53 * @v sin6_src Source socket address
54 * @v sin6_dest Destination socket address
56 * @v len Size of NDP header
57 * @v option_type NDP option type
58 * @ret rc Return status code
60 static int ndp_tx_ll_addr ( struct net_device
*netdev
,
61 struct sockaddr_in6
*sin6_src
,
62 struct sockaddr_in6
*sin6_dest
,
63 const void *data
, size_t len
,
64 unsigned int option_type
) {
65 struct sockaddr_tcpip
*st_src
=
66 ( ( struct sockaddr_tcpip
* ) sin6_src
);
67 struct sockaddr_tcpip
*st_dest
=
68 ( ( struct sockaddr_tcpip
* ) sin6_dest
);
69 struct ll_protocol
*ll_protocol
= netdev
->ll_protocol
;
70 struct io_buffer
*iobuf
;
71 struct ndp_ll_addr_option
*ll_addr_opt
;
72 union ndp_header
*ndp
;
76 /* Allocate and populate buffer */
77 option_len
= ( ( sizeof ( *ll_addr_opt
) +
78 ll_protocol
->ll_addr_len
+ NDP_OPTION_BLKSZ
- 1 ) &
79 ~( NDP_OPTION_BLKSZ
- 1 ) );
80 iobuf
= alloc_iob ( MAX_LL_NET_HEADER_LEN
+ len
+ option_len
);
83 iob_reserve ( iobuf
, MAX_LL_NET_HEADER_LEN
);
84 memcpy ( iob_put ( iobuf
, len
), data
, len
);
85 ll_addr_opt
= iob_put ( iobuf
, option_len
);
86 ll_addr_opt
->header
.type
= option_type
;
87 ll_addr_opt
->header
.blocks
= ( option_len
/ NDP_OPTION_BLKSZ
);
88 memcpy ( ll_addr_opt
->ll_addr
, netdev
->ll_addr
,
89 ll_protocol
->ll_addr_len
);
91 ndp
->icmp
.chksum
= tcpip_chksum ( ndp
, ( len
+ option_len
) );
94 if ( ( rc
= tcpip_tx ( iobuf
, &icmpv6_protocol
, st_src
, st_dest
,
95 netdev
, &ndp
->icmp
.chksum
) ) != 0 ) {
96 DBGC ( netdev
, "NDP %s could not transmit packet: %s\n",
97 netdev
->name
, strerror ( rc
) );
105 * Transmit NDP neighbour discovery request
107 * @v netdev Network device
108 * @v net_protocol Network-layer protocol
109 * @v net_dest Destination network-layer address
110 * @v net_source Source network-layer address
111 * @ret rc Return status code
113 static int ndp_tx_request ( struct net_device
*netdev
,
114 struct net_protocol
*net_protocol __unused
,
115 const void *net_dest
, const void *net_source
) {
116 struct sockaddr_in6 sin6_src
;
117 struct sockaddr_in6 sin6_dest
;
118 struct ndp_neighbour_header neigh
;
121 /* Construct source address */
122 memset ( &sin6_src
, 0, sizeof ( sin6_src
) );
123 sin6_src
.sin6_family
= AF_INET6
;
124 memcpy ( &sin6_src
.sin6_addr
, net_source
,
125 sizeof ( sin6_src
.sin6_addr
) );
127 /* Construct multicast destination address */
128 memset ( &sin6_dest
, 0, sizeof ( sin6_dest
) );
129 sin6_dest
.sin6_family
= AF_INET6
;
130 sin6_dest
.sin6_scope_id
= netdev
->index
;
131 ipv6_solicited_node ( &sin6_dest
.sin6_addr
, net_dest
);
133 /* Construct neighbour header */
134 memset ( &neigh
, 0, sizeof ( neigh
) );
135 neigh
.icmp
.type
= ICMPV6_NEIGHBOUR_SOLICITATION
;
136 memcpy ( &neigh
.target
, net_dest
, sizeof ( neigh
.target
) );
138 /* Transmit neighbour discovery packet */
139 if ( ( rc
= ndp_tx_ll_addr ( netdev
, &sin6_src
, &sin6_dest
, &neigh
,
141 NDP_OPT_LL_SOURCE
) ) != 0 )
147 /** NDP neighbour discovery protocol */
148 struct neighbour_discovery ndp_discovery
= {
150 .tx_request
= ndp_tx_request
,
154 * Transmit NDP router solicitation
156 * @v netdev Network device
157 * @ret rc Return status code
159 static int ndp_tx_router_solicitation ( struct net_device
*netdev
) {
160 struct ndp_router_solicitation_header rsol
;
161 struct sockaddr_in6 sin6_dest
;
164 /* Construct multicast destination address */
165 memset ( &sin6_dest
, 0, sizeof ( sin6_dest
) );
166 sin6_dest
.sin6_family
= AF_INET6
;
167 sin6_dest
.sin6_scope_id
= netdev
->index
;
168 ipv6_all_routers ( &sin6_dest
.sin6_addr
);
170 /* Construct router solicitation */
171 memset ( &rsol
, 0, sizeof ( rsol
) );
172 rsol
.icmp
.type
= ICMPV6_ROUTER_SOLICITATION
;
174 /* Transmit packet */
175 if ( ( rc
= ndp_tx_ll_addr ( netdev
, NULL
, &sin6_dest
, &rsol
,
176 sizeof ( rsol
), NDP_OPT_LL_SOURCE
) ) !=0)
183 * Process NDP neighbour solicitation source link-layer address option
185 * @v netdev Network device
186 * @v sin6_src Source socket address
188 * @v option NDP option
189 * @v len NDP option length
190 * @ret rc Return status code
193 ndp_rx_neighbour_solicitation_ll_source ( struct net_device
*netdev
,
194 struct sockaddr_in6
*sin6_src
,
195 union ndp_header
*ndp
,
196 union ndp_option
*option
,
198 struct ndp_neighbour_header
*neigh
= &ndp
->neigh
;
199 struct ndp_ll_addr_option
*ll_addr_opt
= &option
->ll_addr
;
200 struct ll_protocol
*ll_protocol
= netdev
->ll_protocol
;
203 /* Silently ignore neighbour solicitations for addresses we do
206 if ( ! ipv6_has_addr ( netdev
, &neigh
->target
) )
210 if ( offsetof ( typeof ( *ll_addr_opt
),
211 ll_addr
[ll_protocol
->ll_addr_len
] ) > len
) {
212 DBGC ( netdev
, "NDP %s neighbour solicitation link-layer "
213 "address option too short at %zd bytes\n",
218 /* Create or update neighbour cache entry */
219 if ( ( rc
= neighbour_define ( netdev
, &ipv6_protocol
,
220 &sin6_src
->sin6_addr
,
221 ll_addr_opt
->ll_addr
) ) != 0 ) {
222 DBGC ( netdev
, "NDP %s could not define %s => %s: %s\n",
223 netdev
->name
, inet6_ntoa ( &sin6_src
->sin6_addr
),
224 ll_protocol
->ntoa ( ll_addr_opt
->ll_addr
),
229 /* Convert neighbour header to advertisement */
230 memset ( neigh
, 0, offsetof ( typeof ( *neigh
), target
) );
231 neigh
->icmp
.type
= ICMPV6_NEIGHBOUR_ADVERTISEMENT
;
232 neigh
->flags
= ( NDP_NEIGHBOUR_SOLICITED
| NDP_NEIGHBOUR_OVERRIDE
);
234 /* Send neighbour advertisement */
235 if ( ( rc
= ndp_tx_ll_addr ( netdev
, NULL
, sin6_src
, neigh
,
237 NDP_OPT_LL_TARGET
) ) != 0 )
244 * Process NDP neighbour advertisement target link-layer address option
246 * @v netdev Network device
247 * @v sin6_src Source socket address
249 * @v option NDP option
250 * @v len NDP option length
251 * @ret rc Return status code
254 ndp_rx_neighbour_advertisement_ll_target ( struct net_device
*netdev
,
255 struct sockaddr_in6
*sin6_src
257 union ndp_header
*ndp
,
258 union ndp_option
*option
,
260 struct ndp_neighbour_header
*neigh
= &ndp
->neigh
;
261 struct ndp_ll_addr_option
*ll_addr_opt
= &option
->ll_addr
;
262 struct ll_protocol
*ll_protocol
= netdev
->ll_protocol
;
266 if ( offsetof ( typeof ( *ll_addr_opt
),
267 ll_addr
[ll_protocol
->ll_addr_len
] ) > len
) {
268 DBGC ( netdev
, "NDP %s neighbour advertisement link-layer "
269 "address option too short at %zd bytes\n",
274 /* Update neighbour cache entry, if any */
275 if ( ( rc
= neighbour_update ( netdev
, &ipv6_protocol
, &neigh
->target
,
276 ll_addr_opt
->ll_addr
) ) != 0 ) {
277 DBGC ( netdev
, "NDP %s could not update %s => %s: %s\n",
278 netdev
->name
, inet6_ntoa ( &neigh
->target
),
279 ll_protocol
->ntoa ( ll_addr_opt
->ll_addr
),
288 * Process NDP router advertisement source link-layer address option
290 * @v netdev Network device
291 * @v sin6_src Source socket address
293 * @v option NDP option
294 * @v len NDP option length
295 * @ret rc Return status code
298 ndp_rx_router_advertisement_ll_source ( struct net_device
*netdev
,
299 struct sockaddr_in6
*sin6_src
,
300 union ndp_header
*ndp __unused
,
301 union ndp_option
*option
, size_t len
) {
302 struct ndp_ll_addr_option
*ll_addr_opt
= &option
->ll_addr
;
303 struct ll_protocol
*ll_protocol
= netdev
->ll_protocol
;
307 if ( offsetof ( typeof ( *ll_addr_opt
),
308 ll_addr
[ll_protocol
->ll_addr_len
] ) > len
) {
309 DBGC ( netdev
, "NDP %s router advertisement link-layer address "
310 "option too short at %zd bytes\n", netdev
->name
, len
);
314 /* Define neighbour cache entry */
315 if ( ( rc
= neighbour_define ( netdev
, &ipv6_protocol
,
316 &sin6_src
->sin6_addr
,
317 ll_addr_opt
->ll_addr
) ) != 0 ) {
318 DBGC ( netdev
, "NDP %s could not define %s => %s: %s\n",
319 netdev
->name
, inet6_ntoa ( &sin6_src
->sin6_addr
),
320 ll_protocol
->ntoa ( ll_addr_opt
->ll_addr
),
329 * Process NDP router advertisement prefix information option
331 * @v netdev Network device
332 * @v sin6_src Source socket address
334 * @v option NDP option
335 * @v len NDP option length
336 * @ret rc Return status code
339 ndp_rx_router_advertisement_prefix ( struct net_device
*netdev
,
340 struct sockaddr_in6
*sin6_src
,
341 union ndp_header
*ndp
,
342 union ndp_option
*option
, size_t len
) {
343 struct ndp_router_advertisement_header
*radv
= &ndp
->radv
;
344 struct ndp_prefix_information_option
*prefix_opt
= &option
->prefix
;
347 if ( sizeof ( *prefix_opt
) > len
) {
348 DBGC ( netdev
, "NDP %s router advertisement prefix option too "
349 "short at %zd bytes\n", netdev
->name
, len
);
353 DBGC ( netdev
, "NDP %s found %sdefault router %s ",
354 netdev
->name
, ( radv
->lifetime ?
"" : "non-" ),
355 inet6_ntoa ( &sin6_src
->sin6_addr
) );
356 DBGC ( netdev
, "for %s-link %sautonomous prefix %s/%d\n",
357 ( ( prefix_opt
->flags
& NDP_PREFIX_ON_LINK
) ?
"on" : "off" ),
358 ( ( prefix_opt
->flags
& NDP_PREFIX_AUTONOMOUS
) ?
"" : "non-" ),
359 inet6_ntoa ( &prefix_opt
->prefix
), prefix_opt
->prefix_len
);
364 /** An NDP option handler */
365 struct ndp_option_handler
{
371 * Handle received option
373 * @v netdev Network device
374 * @v sin6_src Source socket address
376 * @v option NDP option
377 * @ret rc Return status code
379 int ( * rx
) ( struct net_device
*netdev
, struct sockaddr_in6
*sin6_src
,
380 union ndp_header
*ndp
, union ndp_option
*option
,
384 /** NDP option handlers */
385 static struct ndp_option_handler ndp_option_handlers
[] = {
387 .icmp_type
= ICMPV6_NEIGHBOUR_SOLICITATION
,
388 .option_type
= NDP_OPT_LL_SOURCE
,
389 .rx
= ndp_rx_neighbour_solicitation_ll_source
,
392 .icmp_type
= ICMPV6_NEIGHBOUR_ADVERTISEMENT
,
393 .option_type
= NDP_OPT_LL_TARGET
,
394 .rx
= ndp_rx_neighbour_advertisement_ll_target
,
397 .icmp_type
= ICMPV6_ROUTER_ADVERTISEMENT
,
398 .option_type
= NDP_OPT_LL_SOURCE
,
399 .rx
= ndp_rx_router_advertisement_ll_source
,
402 .icmp_type
= ICMPV6_ROUTER_ADVERTISEMENT
,
403 .option_type
= NDP_OPT_PREFIX
,
404 .rx
= ndp_rx_router_advertisement_prefix
,
409 * Process received NDP option
411 * @v netdev Network device
412 * @v sin6_src Source socket address
414 * @v option NDP option
415 * @v len Option length
416 * @ret rc Return status code
418 static int ndp_rx_option ( struct net_device
*netdev
,
419 struct sockaddr_in6
*sin6_src
, union ndp_header
*ndp
,
420 union ndp_option
*option
, size_t len
) {
421 struct ndp_option_handler
*handler
;
424 /* Locate a suitable option handler, if any */
425 for ( i
= 0 ; i
< ( sizeof ( ndp_option_handlers
) /
426 sizeof ( ndp_option_handlers
[0] ) ) ; i
++ ) {
427 handler
= &ndp_option_handlers
[i
];
428 if ( ( handler
->icmp_type
== ndp
->icmp
.type
) &&
429 ( handler
->option_type
== option
->header
.type
) ) {
430 return handler
->rx ( netdev
, sin6_src
, ndp
,
435 /* Silently ignore unknown options as per RFC 4861 */
440 * Process received NDP packet options
442 * @v netdev Network device
443 * @v sin6_src Source socket address
445 * @v offset Offset to NDP options
446 * @v len Length of NDP packet
447 * @ret rc Return status code
449 static int ndp_rx_options ( struct net_device
*netdev
,
450 struct sockaddr_in6
*sin6_src
,
451 union ndp_header
*ndp
, size_t offset
, size_t len
) {
452 union ndp_option
*option
;
458 if ( len
< offset
) {
459 DBGC ( netdev
, "NDP %s packet too short at %zd bytes (min %zd "
460 "bytes)\n", netdev
->name
, len
, offset
);
464 /* Search for option */
465 option
= ( ( ( void * ) ndp
) + offset
);
466 remaining
= ( len
- offset
);
467 while ( remaining
) {
470 if ( ( remaining
< sizeof ( option
->header
) ) ||
471 ( option
->header
.blocks
== 0 ) ||
472 ( remaining
< ( option
->header
.blocks
*
473 NDP_OPTION_BLKSZ
) ) ) {
474 DBGC ( netdev
, "NDP %s bad option length:\n",
476 DBGC_HDA ( netdev
, 0, option
, remaining
);
479 option_len
= ( option
->header
.blocks
* NDP_OPTION_BLKSZ
);
482 if ( ( rc
= ndp_rx_option ( netdev
, sin6_src
, ndp
, option
,
483 option_len
) ) != 0 )
486 /* Move to next option */
487 option
= ( ( ( void * ) option
) + option_len
);
488 remaining
-= option_len
;
495 * Process received NDP neighbour solicitation or advertisement
497 * @v iobuf I/O buffer
498 * @v netdev Network device
499 * @v sin6_src Source socket address
500 * @v sin6_dest Destination socket address
501 * @ret rc Return status code
503 static int ndp_rx_neighbour ( struct io_buffer
*iobuf
,
504 struct net_device
*netdev
,
505 struct sockaddr_in6
*sin6_src
,
506 struct sockaddr_in6
*sin6_dest __unused
) {
507 union ndp_header
*ndp
= iobuf
->data
;
508 struct ndp_neighbour_header
*neigh
= &ndp
->neigh
;
509 size_t len
= iob_len ( iobuf
);
512 /* Process options */
513 if ( ( rc
= ndp_rx_options ( netdev
, sin6_src
, ndp
,
514 offsetof ( typeof ( *neigh
), option
),
524 * Process received NDP router advertisement
526 * @v iobuf I/O buffer
527 * @v netdev Network device
528 * @v sin6_src Source socket address
529 * @v sin6_dest Destination socket address
530 * @ret rc Return status code
533 ndp_rx_router_advertisement ( struct io_buffer
*iobuf
,
534 struct net_device
*netdev
,
535 struct sockaddr_in6
*sin6_src
,
536 struct sockaddr_in6
*sin6_dest __unused
) {
537 union ndp_header
*ndp
= iobuf
->data
;
538 struct ndp_router_advertisement_header
*radv
= &ndp
->radv
;
539 struct in6_addr
*router
= &sin6_src
->sin6_addr
;
540 size_t len
= iob_len ( iobuf
);
543 /* Process options */
544 if ( ( rc
= ndp_rx_options ( netdev
, sin6_src
, ndp
,
545 offsetof ( typeof ( *radv
), option
),
549 /* Pass to IPv6 autoconfiguration */
550 if ( ( rc
= ipv6conf_rx_router_advertisement ( netdev
, router
,
560 /** NDP ICMPv6 handlers */
561 struct icmpv6_handler ndp_handlers
[] __icmpv6_handler
= {
563 .type
= ICMPV6_NEIGHBOUR_SOLICITATION
,
564 .rx
= ndp_rx_neighbour
,
567 .type
= ICMPV6_NEIGHBOUR_ADVERTISEMENT
,
568 .rx
= ndp_rx_neighbour
,
571 .type
= ICMPV6_ROUTER_ADVERTISEMENT
,
572 .rx
= ndp_rx_router_advertisement
,
576 /****************************************************************************
582 /** An NDP prefix settings block */
583 struct ndp_prefix_settings
{
584 /** Settings interface */
585 struct settings settings
;
588 /** Prefix information option */
589 struct ndp_prefix_information_option
*prefix
;
592 /** An NDP settings block */
593 struct ndp_settings
{
594 /** Reference counter */
595 struct refcnt refcnt
;
596 /** Settings interface */
597 struct settings settings
;
598 /** Router address */
599 struct in6_addr router
;
600 /** Router lifetime */
601 unsigned int lifetime
;
602 /** Length of NDP options */
605 union ndp_option options
[0];
608 /** NDP settings scope */
609 static const struct settings_scope ndp_settings_scope
;
614 * @v type NDP option type
615 * @v offset Starting offset of data
616 * @v len Length of data (or 0 to use all remaining data)
619 #define NDP_TAG( type, offset, len ) \
620 ( ( (len) << 16 ) | ( (offset) << 8 ) | (type) )
623 * Extract NDP tag type
626 * @ret type NDP option type
628 #define NDP_TAG_TYPE( tag ) ( ( (tag) >> 0 ) & 0xff )
631 * Extract NDP tag offset
634 * @ret offset Starting offset of data
636 #define NDP_TAG_OFFSET( tag ) ( ( (tag) >> 8 ) & 0xff )
639 * Extract NDP tag length
642 * @ret len Length of data (or 0 to use all remaining data)
644 #define NDP_TAG_LEN( tag ) ( ( (tag) >> 16 ) & 0xff )
647 * Extract NDP tag instance
650 * @ret instance Instance
652 #define NDP_TAG_INSTANCE( tag ) ( ( (tag) >> 24 ) & 0xff )
655 * Check applicability of NDP setting
657 * @v settings Settings block
658 * @v setting Setting to fetch
659 * @ret applies Setting applies within this settings block
661 static int ndp_applies ( struct settings
*settings __unused
,
662 const struct setting
*setting
) {
664 return ( setting
->scope
== &ndp_settings_scope
);
668 * Fetch value of NDP setting
670 * @v settings Settings block
671 * @v setting Setting to fetch
672 * @v data Buffer to fill with setting data
673 * @v len Length of buffer
674 * @ret len Length of setting data, or negative error
676 static int ndp_fetch ( struct settings
*settings
,
677 struct setting
*setting
,
678 void *data
, size_t len
) {
679 struct ndp_settings
*ndpset
=
680 container_of ( settings
, struct ndp_settings
, settings
);
681 struct net_device
*netdev
=
682 container_of ( settings
->parent
, struct net_device
,
684 union ndp_option
*option
;
685 unsigned int tag_type
;
686 unsigned int tag_offset
;
687 unsigned int tag_len
;
688 unsigned int tag_instance
;
693 /* Parse setting tag */
694 tag_type
= NDP_TAG_TYPE ( setting
->tag
);
695 tag_offset
= NDP_TAG_OFFSET ( setting
->tag
);
696 tag_len
= NDP_TAG_LEN ( setting
->tag
);
697 tag_instance
= NDP_TAG_INSTANCE ( setting
->tag
);
699 /* Scan through NDP options for requested type. We can assume
700 * that the options are well-formed, otherwise they would have
701 * been rejected prior to being stored.
703 for ( offset
= 0 ; offset
< ndpset
->len
; offset
+= option_len
) {
705 /* Calculate option length */
706 option
= ( ( ( void * ) ndpset
->options
) + offset
);
707 option_len
= ( option
->header
.blocks
* NDP_OPTION_BLKSZ
);
709 /* Skip options that do not match this tag */
710 if ( option
->header
.type
!= tag_type
)
713 /* Skip previous instances of this option */
714 if ( tag_instance
-- != 0 )
718 if ( ( tag_offset
+ tag_len
) > option_len
) {
719 DBGC ( netdev
, "NDP %s option %d too short\n",
720 netdev
->name
, tag_type
);
724 tag_len
= ( option_len
- tag_offset
);
725 option_data
= ( ( ( void * ) option
) + tag_offset
);
727 /* Copy data to output buffer */
730 memcpy ( data
, option_data
, len
);
732 /* Default to hex if no type is specified */
733 if ( ! setting
->type
)
734 setting
->type
= &setting_type_hex
;
742 /** NDP settings operations */
743 static struct settings_operations ndp_settings_operations
= {
744 .applies
= ndp_applies
,
749 * Check applicability of NDP per-prefix setting
751 * @v settings Settings block
752 * @v setting Setting to fetch
753 * @ret applies Setting applies within this settings block
755 static int ndp_prefix_applies ( struct settings
*settings __unused
,
756 const struct setting
*setting
) {
758 return ( setting
->scope
== &ipv6_scope
);
762 * Fetch value of NDP IPv6 address setting
764 * @v settings Settings block
765 * @v data Buffer to fill with setting data
766 * @v len Length of buffer
767 * @ret len Length of setting data, or negative error
769 static int ndp_prefix_fetch_ip6 ( struct settings
*settings
, void *data
,
771 struct ndp_prefix_settings
*prefset
=
772 container_of ( settings
, struct ndp_prefix_settings
, settings
);
773 struct ndp_settings
*ndpset
=
774 container_of ( settings
->parent
, struct ndp_settings
, settings
);
775 struct net_device
*netdev
=
776 container_of ( ndpset
->settings
.parent
, struct net_device
,
778 struct ndp_prefix_information_option
*prefix
= prefset
->prefix
;
782 /* Skip dead prefixes */
783 if ( ! prefix
->valid
)
786 /* Construct IPv6 address via SLAAC, if applicable */
787 memcpy ( &ip6
, &prefix
->prefix
, sizeof ( ip6
) );
788 if ( prefix
->flags
& NDP_PREFIX_AUTONOMOUS
) {
789 prefix_len
= ipv6_eui64 ( &ip6
, netdev
);
790 if ( prefix_len
< 0 )
792 if ( prefix_len
!= prefix
->prefix_len
)
796 /* Fill in IPv6 address */
797 if ( len
> sizeof ( ip6
) )
798 len
= sizeof ( ip6
);
799 memcpy ( data
, &ip6
, len
);
801 return sizeof ( ip6
);
805 * Fetch value of NDP prefix length setting
807 * @v settings Settings block
808 * @v data Buffer to fill with setting data
809 * @v len Length of buffer
810 * @ret len Length of setting data, or negative error
812 static int ndp_prefix_fetch_len6 ( struct settings
*settings
, void *data
,
814 struct ndp_prefix_settings
*prefset
=
815 container_of ( settings
, struct ndp_prefix_settings
, settings
);
816 struct ndp_prefix_information_option
*prefix
= prefset
->prefix
;
819 /* Fill in prefix length */
820 if ( len
>= sizeof ( *len6
) ) {
821 /* We treat an off-link prefix as having a prefix
822 * length covering the entire IPv6 address.
825 *len6
= ( ( prefix
->flags
& NDP_PREFIX_ON_LINK
) ?
826 prefix
->prefix_len
: -1UL );
829 return sizeof ( *len6
);
833 * Fetch value of NDP router address setting
835 * @v settings Settings block
836 * @v data Buffer to fill with setting data
837 * @v len Length of buffer
838 * @ret len Length of setting data, or negative error
840 static int ndp_prefix_fetch_gateway6 ( struct settings
*settings
,
841 void *data
, size_t len
) {
842 struct ndp_settings
*ndpset
=
843 container_of ( settings
->parent
, struct ndp_settings
, settings
);
845 /* Treat non-routing router as non-existent */
846 if ( ! ndpset
->lifetime
)
849 /* Fill in router address */
850 if ( len
> sizeof ( ndpset
->router
) )
851 len
= sizeof ( ndpset
->router
);
852 memcpy ( data
, &ndpset
->router
, len
);
854 return sizeof ( ndpset
->router
);
857 /** An NDP per-prefix setting operation */
858 struct ndp_prefix_operation
{
859 /** Generic setting */
860 const struct setting
*setting
;
862 * Fetch value of setting
864 * @v settings Settings block
865 * @v data Buffer to fill with setting data
866 * @v len Length of buffer
867 * @ret len Length of setting data, or negative error
869 int ( * fetch
) ( struct settings
*settings
, void *data
, size_t len
);
872 /** NDP per-prefix settings operations */
873 static struct ndp_prefix_operation ndp_prefix_operations
[] = {
874 { &ip6_setting
, ndp_prefix_fetch_ip6
},
875 { &len6_setting
, ndp_prefix_fetch_len6
},
876 { &gateway6_setting
, ndp_prefix_fetch_gateway6
},
880 * Fetch value of NDP pre-prefix setting
882 * @v settings Settings block
883 * @v setting Setting to fetch
884 * @v data Buffer to fill with setting data
885 * @v len Length of buffer
886 * @ret len Length of setting data, or negative error
888 static int ndp_prefix_fetch ( struct settings
*settings
,
889 struct setting
*setting
,
890 void *data
, size_t len
) {
891 struct ndp_prefix_operation
*op
;
894 /* Handle per-prefix settings */
895 for ( i
= 0 ; i
< ( sizeof ( ndp_prefix_operations
) /
896 sizeof ( ndp_prefix_operations
[0] ) ) ; i
++ ) {
897 op
= &ndp_prefix_operations
[i
];
898 if ( setting_cmp ( setting
, op
->setting
) == 0 )
899 return op
->fetch ( settings
, data
, len
);
905 /** NDP per-prefix settings operations */
906 static struct settings_operations ndp_prefix_settings_operations
= {
907 .applies
= ndp_prefix_applies
,
908 .fetch
= ndp_prefix_fetch
,
912 * Register NDP settings
914 * @v netdev Network device
915 * @v router Router address
916 * @v lifetime Router lifetime
917 * @v options NDP options
918 * @v len Length of options
919 * @ret rc Return status code
921 static int ndp_register_settings ( struct net_device
*netdev
,
922 struct in6_addr
*router
,
923 unsigned int lifetime
,
924 union ndp_option
*options
, size_t len
) {
925 struct settings
*parent
= netdev_settings ( netdev
);
926 union ndp_option
*option
;
927 struct ndp_settings
*ndpset
;
928 struct ndp_prefix_settings
*prefset
;
931 unsigned int prefixes
;
932 unsigned int instance
;
936 /* Count number of prefix options. We can assume that the
937 * options are well-formed, otherwise they would have been
938 * rejected prior to being stored.
940 order
= IPV6_ORDER_PREFIX_ONLY
;
941 for ( prefixes
= 0, offset
= 0 ; offset
< len
; offset
+= option_len
) {
943 /* Skip non-prefix options */
944 option
= ( ( ( void * ) options
) + offset
);
945 option_len
= ( option
->header
.blocks
* NDP_OPTION_BLKSZ
);
946 if ( option
->header
.type
!= NDP_OPT_PREFIX
)
949 /* Count number of prefixes */
952 /* Increase overall order if we have SLAAC addresses */
953 if ( option
->prefix
.flags
& NDP_PREFIX_AUTONOMOUS
)
954 order
= IPV6_ORDER_SLAAC
;
957 /* Allocate and initialise structure */
958 ndpset
= zalloc ( sizeof ( *ndpset
) + len
+
959 ( prefixes
* sizeof ( *prefset
) ) );
964 ref_init ( &ndpset
->refcnt
, NULL
);
965 settings_init ( &ndpset
->settings
, &ndp_settings_operations
,
966 &ndpset
->refcnt
, &ndp_settings_scope
);
967 ndpset
->settings
.order
= order
;
968 memcpy ( &ndpset
->router
, router
, sizeof ( ndpset
->router
) );
969 ndpset
->lifetime
= lifetime
;
971 memcpy ( ndpset
->options
, options
, len
);
972 prefset
= ( ( ( void * ) ndpset
->options
) + len
);
974 /* Register settings */
975 if ( ( rc
= register_settings ( &ndpset
->settings
, parent
,
976 NDP_SETTINGS_NAME
) ) != 0 )
979 /* Construct and register per-prefix settings */
980 for ( instance
= 0, offset
= 0 ; offset
< len
; offset
+= option_len
) {
982 /* Skip non-prefix options */
983 option
= ( ( ( void * ) ndpset
->options
) + offset
);
984 option_len
= ( option
->header
.blocks
* NDP_OPTION_BLKSZ
);
985 if ( option
->header
.type
!= NDP_OPT_PREFIX
)
988 /* Initialise structure */
989 settings_init ( &prefset
->settings
,
990 &ndp_prefix_settings_operations
,
991 &ndpset
->refcnt
, &ndp_settings_scope
);
992 prefset
->settings
.order
=
993 ( ( option
->prefix
.flags
& NDP_PREFIX_AUTONOMOUS
) ?
994 IPV6_ORDER_SLAAC
: IPV6_ORDER_PREFIX_ONLY
);
995 prefset
->prefix
= &option
->prefix
;
996 snprintf ( prefset
->name
, sizeof ( prefset
->name
), "%d",
999 /* Register settings */
1000 if ( ( rc
= register_settings ( &prefset
->settings
,
1002 prefset
->name
) ) != 0 )
1003 goto err_register_prefix
;
1005 /* Move to next per-prefix settings */
1008 assert ( instance
== prefixes
);
1010 ref_put ( &ndpset
->refcnt
);
1013 err_register_prefix
:
1014 unregister_settings ( &ndpset
->settings
);
1016 ref_put ( &ndpset
->refcnt
);
1021 /** DNS server setting */
1022 const struct setting ndp_dns6_setting
__setting ( SETTING_IP6_EXTRA
, dns6
) = {
1024 .description
= "DNS server",
1025 .tag
= NDP_TAG ( NDP_OPT_RDNSS
,
1026 offsetof ( struct ndp_rdnss_option
, addresses
), 0 ),
1027 .type
= &setting_type_ipv6
,
1028 .scope
= &ndp_settings_scope
,
1031 /** DNS search list setting */
1032 const struct setting ndp_dnssl_setting
__setting ( SETTING_IP_EXTRA
, dnssl
) = {
1034 .description
= "DNS search list",
1035 .tag
= NDP_TAG ( NDP_OPT_DNSSL
,
1036 offsetof ( struct ndp_dnssl_option
, names
), 0 ),
1037 .type
= &setting_type_dnssl
,
1038 .scope
= &ndp_settings_scope
,
1041 /****************************************************************************
1043 * IPv6 autoconfiguration
1047 /** An IPv6 configurator */
1049 /** Reference count */
1050 struct refcnt refcnt
;
1051 /** List of configurators */
1052 struct list_head list
;
1054 /** Job control interface */
1055 struct interface job
;
1056 /** DHCPv6 interface */
1057 struct interface dhcp
;
1059 /** Network device being configured */
1060 struct net_device
*netdev
;
1062 /** Retransmission timer */
1063 struct retry_timer timer
;
1066 /** List of IPv6 configurators */
1067 static LIST_HEAD ( ipv6confs
);
1070 * Free IPv6 configurator
1072 * @v refcnt Reference count
1074 static void ipv6conf_free ( struct refcnt
*refcnt
) {
1075 struct ipv6conf
*ipv6conf
=
1076 container_of ( refcnt
, struct ipv6conf
, refcnt
);
1078 netdev_put ( ipv6conf
->netdev
);
1083 * Identify IPv6 configurator by network device
1085 * @v netdev Network device
1086 * @ret ipv6 IPv6 configurator, or NULL
1088 static struct ipv6conf
* ipv6conf_demux ( struct net_device
*netdev
) {
1089 struct ipv6conf
*ipv6conf
;
1091 list_for_each_entry ( ipv6conf
, &ipv6confs
, list
) {
1092 if ( ipv6conf
->netdev
== netdev
)
1099 * Finish IPv6 autoconfiguration
1101 * @v ipv6 IPv6 configurator
1102 * @v rc Reason for finishing
1104 static void ipv6conf_done ( struct ipv6conf
*ipv6conf
, int rc
) {
1106 /* Shut down interfaces */
1107 intf_shutdown ( &ipv6conf
->job
, rc
);
1108 intf_shutdown ( &ipv6conf
->dhcp
, rc
);
1111 stop_timer ( &ipv6conf
->timer
);
1113 /* Remove from list and drop list's reference */
1114 list_del ( &ipv6conf
->list
);
1115 ref_put ( &ipv6conf
->refcnt
);
1119 * Handle IPv6 configurator timer expiry
1121 * @v timer Retry timer
1122 * @v fail Failure indicator
1124 static void ipv6conf_expired ( struct retry_timer
*timer
, int fail
) {
1125 struct ipv6conf
*ipv6conf
=
1126 container_of ( timer
, struct ipv6conf
, timer
);
1128 /* If we have failed, terminate autoconfiguration */
1130 ipv6conf_done ( ipv6conf
, -ETIMEDOUT
);
1134 /* Otherwise, transmit router solicitation and restart timer */
1135 start_timer ( &ipv6conf
->timer
);
1136 ndp_tx_router_solicitation ( ipv6conf
->netdev
);
1140 * Handle router advertisement during IPv6 autoconfiguration
1142 * @v netdev Network device
1143 * @v router Router address
1144 * @v radv Router advertisement
1145 * @v len Length of router advertisement
1146 * @ret rc Return status code
1148 * This function assumes that the router advertisement is well-formed,
1149 * since it must have already passed through option processing.
1152 ipv6conf_rx_router_advertisement ( struct net_device
*netdev
,
1153 struct in6_addr
*router
,
1154 struct ndp_router_advertisement_header
*radv
,
1156 struct ipv6conf
*ipv6conf
;
1161 /* Identify IPv6 configurator, if any */
1162 ipv6conf
= ipv6conf_demux ( netdev
);
1164 /* Do nothing unless IPv6 autoconfiguration is in progress */
1168 /* If this is not the first solicited router advertisement, ignore it */
1169 if ( ! timer_running ( &ipv6conf
->timer
) )
1172 /* Stop router solicitation timer */
1173 stop_timer ( &ipv6conf
->timer
);
1175 /* Register NDP settings */
1176 option_len
= ( len
- offsetof ( typeof ( *radv
), option
) );
1177 if ( ( rc
= ndp_register_settings ( netdev
, router
,
1178 ntohl ( radv
->lifetime
),
1179 radv
->option
, option_len
) ) != 0 )
1182 /* Start DHCPv6 if required */
1183 if ( radv
->flags
& ( NDP_ROUTER_MANAGED
| NDP_ROUTER_OTHER
) ) {
1184 stateful
= ( radv
->flags
& NDP_ROUTER_MANAGED
);
1185 if ( ( rc
= start_dhcpv6 ( &ipv6conf
->dhcp
, netdev
,
1186 stateful
) ) != 0 ) {
1187 DBGC ( netdev
, "NDP %s could not start state%s DHCPv6: "
1188 "%s\n", netdev
->name
,
1189 ( stateful ?
"ful" : "less" ), strerror ( rc
) );
1190 ipv6conf_done ( ipv6conf
, rc
);
1196 /* Otherwise, terminate autoconfiguration */
1197 ipv6conf_done ( ipv6conf
, 0 );
1202 /** IPv6 configurator job interface operations */
1203 static struct interface_operation ipv6conf_job_op
[] = {
1204 INTF_OP ( intf_close
, struct ipv6conf
*, ipv6conf_done
),
1207 /** IPv6 configurator job interface descriptor */
1208 static struct interface_descriptor ipv6conf_job_desc
=
1209 INTF_DESC ( struct ipv6conf
, job
, ipv6conf_job_op
);
1211 /** IPv6 configurator DHCPv6 interface operations */
1212 static struct interface_operation ipv6conf_dhcp_op
[] = {
1213 INTF_OP ( intf_close
, struct ipv6conf
*, ipv6conf_done
),
1216 /** IPv6 configurator DHCPv6 interface descriptor */
1217 static struct interface_descriptor ipv6conf_dhcp_desc
=
1218 INTF_DESC ( struct ipv6conf
, dhcp
, ipv6conf_dhcp_op
);
1221 * Start IPv6 autoconfiguration
1223 * @v job Job control interface
1224 * @v netdev Network device
1225 * @ret rc Return status code
1227 int start_ipv6conf ( struct interface
*job
, struct net_device
*netdev
) {
1228 struct ipv6conf
*ipv6conf
;
1230 /* Allocate and initialise structure */
1231 ipv6conf
= zalloc ( sizeof ( *ipv6conf
) );
1234 ref_init ( &ipv6conf
->refcnt
, ipv6conf_free
);
1235 intf_init ( &ipv6conf
->job
, &ipv6conf_job_desc
, &ipv6conf
->refcnt
);
1236 intf_init ( &ipv6conf
->dhcp
, &ipv6conf_dhcp_desc
, &ipv6conf
->refcnt
);
1237 timer_init ( &ipv6conf
->timer
, ipv6conf_expired
, &ipv6conf
->refcnt
);
1238 ipv6conf
->netdev
= netdev_get ( netdev
);
1240 /* Start timer to initiate router solicitation */
1241 start_timer_nodelay ( &ipv6conf
->timer
);
1243 /* Attach parent interface, transfer reference to list, and return */
1244 intf_plug_plug ( &ipv6conf
->job
, job
);
1245 list_add ( &ipv6conf
->list
, &ipv6confs
);
1249 /** IPv6 network device configurator */
1250 struct net_device_configurator ipv6_configurator __net_device_configurator
= {
1252 .start
= start_ipv6conf
,