diff options
author | Michael Brown | 2016-07-19 15:16:51 +0200 |
---|---|---|
committer | Michael Brown | 2016-07-19 15:35:30 +0200 |
commit | 1fdc7da4358bda233b0f1a9cb8cd27c92830f6b9 (patch) | |
tree | 06adb5f448c614f33dd8a023c9e1bf9516305db9 /src/net | |
parent | [dhcpv6] Expose IPv6 address setting acquired through DHCPv6 (diff) | |
download | ipxe-1fdc7da4358bda233b0f1a9cb8cd27c92830f6b9.tar.gz ipxe-1fdc7da4358bda233b0f1a9cb8cd27c92830f6b9.tar.xz ipxe-1fdc7da4358bda233b0f1a9cb8cd27c92830f6b9.zip |
[ipv6] Expose IPv6 link-local address settings
Originally-implemented-by: Hannes Reinecke <hare@suse.de>
Originally-implemented-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net')
-rw-r--r-- | src/net/ipv6.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/src/net/ipv6.c b/src/net/ipv6.c index 78d61369..cdd6640c 100644 --- a/src/net/ipv6.c +++ b/src/net/ipv6.c @@ -1089,6 +1089,115 @@ const struct setting gateway6_setting __setting ( SETTING_IP6, gateway6 ) = { }; /** + * Check applicability of IPv6 link-local address setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @ret applies Setting applies within this settings block + */ +static int ipv6_applies ( struct settings *settings __unused, + const struct setting *setting ) { + + return ( setting->scope == &ipv6_scope ); +} + +/** + * Fetch IPv6 link-local address setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int ipv6_fetch ( struct settings *settings, struct setting *setting, + void *data, size_t len ) { + struct net_device *netdev = + container_of ( settings->parent, struct net_device, + settings.settings ); + struct in6_addr ip6; + uint8_t *len6; + int prefix_len; + int rc; + + /* Construct link-local address from EUI-64 as per RFC 2464 */ + memset ( &ip6, 0, sizeof ( ip6 ) ); + prefix_len = ipv6_link_local ( &ip6, netdev ); + if ( prefix_len < 0 ) { + rc = prefix_len; + return rc; + } + + /* Handle setting */ + if ( setting_cmp ( setting, &ip6_setting ) == 0 ) { + + /* Return link-local ip6 */ + if ( len > sizeof ( ip6 ) ) + len = sizeof ( ip6 ); + memcpy ( data, &ip6, len ); + return sizeof ( ip6 ); + + } else if ( setting_cmp ( setting, &len6_setting ) == 0 ) { + + /* Return prefix length */ + if ( len ) { + len6 = data; + *len6 = prefix_len; + } + return sizeof ( *len6 ); + + } + + return -ENOENT; +} + +/** IPv6 link-local address settings operations */ +static struct settings_operations ipv6_settings_operations = { + .applies = ipv6_applies, + .fetch = ipv6_fetch, +}; + +/** IPv6 link-local address settings */ +struct ipv6_settings { + /** Reference counter */ + struct refcnt refcnt; + /** Settings interface */ + struct settings settings; +}; + +/** + * Register IPv6 link-local address settings + * + * @v netdev Network device + * @ret rc Return status code + */ +static int ipv6_register_settings ( struct net_device *netdev ) { + struct settings *parent = netdev_settings ( netdev ); + struct ipv6_settings *ipv6set; + int rc; + + /* Allocate and initialise structure */ + ipv6set = zalloc ( sizeof ( *ipv6set ) ); + if ( ! ipv6set ) { + rc = -ENOMEM; + goto err_alloc; + } + ref_init ( &ipv6set->refcnt, NULL ); + settings_init ( &ipv6set->settings, &ipv6_settings_operations, + &ipv6set->refcnt, &ipv6_scope ); + + /* Register settings */ + if ( ( rc = register_settings ( &ipv6set->settings, parent, + IPV6_SETTINGS_NAME ) ) != 0 ) + goto err_register; + + err_register: + ref_put ( &ipv6set->refcnt ); + err_alloc: + return rc; +} + +/** * Create IPv6 network device * * @v netdev Network device @@ -1116,6 +1225,10 @@ static int ipv6_probe ( struct net_device *netdev ) { if ( ! miniroute ) return -ENOMEM; + /* Register link-local address settings */ + if ( ( rc = ipv6_register_settings ( netdev ) ) != 0 ) + return rc; + return 0; } |