diff options
Diffstat (limited to 'src/net')
-rw-r--r-- | src/net/ndp.c | 2 | ||||
-rw-r--r-- | src/net/udp/dhcpv6.c | 111 |
2 files changed, 96 insertions, 17 deletions
diff --git a/src/net/ndp.c b/src/net/ndp.c index 373a9360b..3c555f4a3 100644 --- a/src/net/ndp.c +++ b/src/net/ndp.c @@ -1221,7 +1221,7 @@ ipv6conf_rx_router_advertisement ( struct net_device *netdev, /* Start DHCPv6 if required */ if ( radv->flags & ( NDP_ROUTER_MANAGED | NDP_ROUTER_OTHER ) ) { stateful = ( radv->flags & NDP_ROUTER_MANAGED ); - if ( ( rc = start_dhcpv6 ( &ipv6conf->dhcp, netdev, + if ( ( rc = start_dhcpv6 ( &ipv6conf->dhcp, netdev, router, stateful ) ) != 0 ) { DBGC ( netdev, "NDP %s could not start state%s DHCPv6: " "%s\n", netdev->name, diff --git a/src/net/udp/dhcpv6.c b/src/net/udp/dhcpv6.c index 9e27dec6f..a49109894 100644 --- a/src/net/udp/dhcpv6.c +++ b/src/net/udp/dhcpv6.c @@ -268,6 +268,8 @@ struct dhcpv6_settings { struct settings settings; /** Leased address */ struct in6_addr lease; + /** Router address */ + struct in6_addr router; /** Option list */ struct dhcpv6_option_list options; }; @@ -283,25 +285,21 @@ static int dhcpv6_applies ( struct settings *settings __unused, const struct setting *setting ) { return ( ( setting->scope == &dhcpv6_scope ) || - ( setting_cmp ( setting, &ip6_setting ) == 0 ) ); + ( setting->scope == &ipv6_settings_scope ) ); } /** * Fetch value of DHCPv6 leased address * - * @v dhcpset DHCPv6 settings + * @v dhcpv6set DHCPv6 settings * @v data Buffer to fill with setting data * @v len Length of buffer * @ret len Length of setting data, or negative error */ -static int dhcpv6_fetch_lease ( struct dhcpv6_settings *dhcpv6set, - void *data, size_t len ) { +static int dhcpv6_fetch_ip6 ( struct dhcpv6_settings *dhcpv6set, + void *data, size_t len ) { struct in6_addr *lease = &dhcpv6set->lease; - /* Do nothing unless a leased address exists */ - if ( IN6_IS_ADDR_UNSPECIFIED ( lease ) ) - return -ENOENT; - /* Copy leased address */ if ( len > sizeof ( *lease ) ) len = sizeof ( *lease ); @@ -311,6 +309,72 @@ static int dhcpv6_fetch_lease ( struct dhcpv6_settings *dhcpv6set, } /** + * Fetch value of DHCPv6 implicit address prefix length + * + * @v dhcpv6set DHCPv6 settings + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int dhcpv6_fetch_len6 ( struct dhcpv6_settings *dhcpv6set __unused, + void *data, size_t len ) { + uint8_t *len6 = data; + + /* Default to assuming this is the only address on the link. + * If the address falls within a known prefix, then the IPv6 + * routing table construction logic will match it against that + * prefix. + */ + if ( len ) + *len6 = IPV6_MAX_PREFIX_LEN; + + return sizeof ( *len6 ); +} + +/** + * Fetch value of DHCPv6 router address + * + * @v dhcpv6set DHCPv6 settings + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int dhcpv6_fetch_gateway6 ( struct dhcpv6_settings *dhcpv6set, + void *data, size_t len ) { + struct in6_addr *router = &dhcpv6set->router; + + /* Copy router address */ + if ( len > sizeof ( *router ) ) + len = sizeof ( *router ); + memcpy ( data, router, len ); + + return sizeof ( *router ); +} + +/** A DHCPv6 address setting operation */ +struct dhcpv6_address_operation { + /** Generic setting */ + const struct setting *setting; + /** + * Fetch value of setting + * + * @v dhcpv6set DHCPv6 settings + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ + int ( * fetch ) ( struct dhcpv6_settings *dhcpv6set, + void *data, size_t len ); +}; + +/** DHCPv6 address settings operations */ +static struct dhcpv6_address_operation dhcpv6_address_operations[] = { + { &ip6_setting, dhcpv6_fetch_ip6 }, + { &len6_setting, dhcpv6_fetch_len6 }, + { &gateway6_setting, dhcpv6_fetch_gateway6 }, +}; + +/** * Fetch value of DHCPv6 setting * * @v settings Settings block @@ -325,11 +389,20 @@ static int dhcpv6_fetch ( struct settings *settings, struct dhcpv6_settings *dhcpv6set = container_of ( settings, struct dhcpv6_settings, settings ); const union dhcpv6_any_option *option; + struct dhcpv6_address_operation *op; size_t option_len; - - /* Handle leased address */ - if ( setting_cmp ( setting, &ip6_setting ) == 0 ) - return dhcpv6_fetch_lease ( dhcpv6set, data, len ); + unsigned int i; + + /* Handle address settings */ + for ( i = 0 ; i < ( sizeof ( dhcpv6_address_operations ) / + sizeof ( dhcpv6_address_operations[0] ) ) ; i++ ) { + op = &dhcpv6_address_operations[i]; + if ( setting_cmp ( setting, op->setting ) != 0 ) + continue; + if ( IN6_IS_ADDR_UNSPECIFIED ( &dhcpv6set->lease ) ) + return -ENOENT; + return op->fetch ( dhcpv6set, data, len ); + } /* Find option */ option = dhcpv6_option ( &dhcpv6set->options, setting->tag ); @@ -354,11 +427,12 @@ static struct settings_operations dhcpv6_settings_operations = { * Register DHCPv6 options as network device settings * * @v lease DHCPv6 leased address + * @v router DHCPv6 router address * @v options DHCPv6 option list * @v parent Parent settings block * @ret rc Return status code */ -static int dhcpv6_register ( struct in6_addr *lease, +static int dhcpv6_register ( struct in6_addr *lease, struct in6_addr *router, struct dhcpv6_option_list *options, struct settings *parent ) { struct dhcpv6_settings *dhcpv6set; @@ -382,6 +456,7 @@ static int dhcpv6_register ( struct in6_addr *lease, dhcpv6set->options.data = data; dhcpv6set->options.len = len; memcpy ( &dhcpv6set->lease, lease, sizeof ( dhcpv6set->lease ) ); + memcpy ( &dhcpv6set->router, router, sizeof ( dhcpv6set->router ) ); /* Register settings */ if ( ( rc = register_settings ( &dhcpv6set->settings, parent, @@ -501,6 +576,8 @@ struct dhcpv6_session { /** Network device being configured */ struct net_device *netdev; + /** Router address */ + struct in6_addr router; /** Transaction ID */ uint8_t xid[3]; /** Identity association ID */ @@ -876,8 +953,8 @@ static int dhcpv6_rx ( struct dhcpv6_session *dhcpv6, } /* Register settings */ - if ( ( rc = dhcpv6_register ( &dhcpv6->lease, &options, - parent ) ) != 0 ) { + if ( ( rc = dhcpv6_register ( &dhcpv6->lease, &dhcpv6->router, + &options, parent ) ) != 0 ) { DBGC ( dhcpv6, "DHCPv6 %s could not register settings: %s\n", dhcpv6->netdev->name, strerror ( rc ) ); goto done; @@ -915,11 +992,12 @@ static struct interface_descriptor dhcpv6_xfer_desc = * * @v job Job control interface * @v netdev Network device + * @v router Router address * @v stateful Perform stateful address autoconfiguration * @ret rc Return status code */ int start_dhcpv6 ( struct interface *job, struct net_device *netdev, - int stateful ) { + struct in6_addr *router, int stateful ) { struct ll_protocol *ll_protocol = netdev->ll_protocol; struct dhcpv6_session *dhcpv6; struct { @@ -944,6 +1022,7 @@ int start_dhcpv6 ( struct interface *job, struct net_device *netdev, intf_init ( &dhcpv6->job, &dhcpv6_job_desc, &dhcpv6->refcnt ); intf_init ( &dhcpv6->xfer, &dhcpv6_xfer_desc, &dhcpv6->refcnt ); dhcpv6->netdev = netdev_get ( netdev ); + memcpy ( &dhcpv6->router, router, sizeof ( dhcpv6->router ) ); xid = random(); memcpy ( dhcpv6->xid, &xid, sizeof ( dhcpv6->xid ) ); dhcpv6->start = currticks(); |