]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[ipv6] Expose IPv6 link-local address settings
authorMichael Brown <mcb30@ipxe.org>
Tue, 19 Jul 2016 13:16:51 +0000 (14:16 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 19 Jul 2016 13:35:30 +0000 (14:35 +0100)
Originally-implemented-by: Hannes Reinecke <hare@suse.de>
Originally-implemented-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/include/ipxe/ipv6.h
src/net/ipv6.c

index b500382c19c2d195c7ab92dbfa3ae68af41a7594..86c8ff924b00030ef86003bf9f13878297ca4749 100644 (file)
@@ -238,6 +238,9 @@ static inline void ipv6_all_routers ( struct in6_addr *addr ) {
        addr->s6_addr[15] = 2;
 }
 
+/** IPv6 link-local address settings block name */
+#define IPV6_SETTINGS_NAME "link"
+
 extern struct list_head ipv6_miniroutes;
 
 extern struct net_protocol ipv6_protocol __net_protocol;
index 78d61369ff5b02917f37feab7390e5597e3a1314..cdd6640c7e4764cf5841a672a1f79f25ef1e5510 100644 (file)
@@ -1088,6 +1088,115 @@ const struct setting gateway6_setting __setting ( SETTING_IP6, gateway6 ) = {
        .scope = &ipv6_scope,
 };
 
+/**
+ * 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
  *
@@ -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;
 }