summaryrefslogtreecommitdiffstats
path: root/src/net/ipv6.c
diff options
context:
space:
mode:
authorMichael Brown2016-07-19 15:16:51 +0200
committerMichael Brown2016-07-19 15:35:30 +0200
commit1fdc7da4358bda233b0f1a9cb8cd27c92830f6b9 (patch)
tree06adb5f448c614f33dd8a023c9e1bf9516305db9 /src/net/ipv6.c
parent[dhcpv6] Expose IPv6 address setting acquired through DHCPv6 (diff)
downloadipxe-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/ipv6.c')
-rw-r--r--src/net/ipv6.c113
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;
}