[Settings] Add per-netdevice settings block
authorMichael Brown <mcb30@etherboot.org>
Thu, 20 Mar 2008 21:06:03 +0000 (21:06 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 20 Mar 2008 21:06:53 +0000 (21:06 +0000)
Add a configuration settings block for each net device.  This will
provide the parent scope for settings applicable only to that network
device (e.g. non-volatile options stored on the NIC, options obtained via
DHCP, etc.).

Expose the MAC address as a setting.

src/include/gpxe/dhcp.h
src/include/gpxe/errfile.h
src/include/gpxe/netdevice.h
src/include/gpxe/settings.h
src/net/netdev_settings.c [new file with mode: 0644]
src/net/netdevice.c

index 6db0e02..3da9652 100644 (file)
@@ -177,6 +177,15 @@ struct job_interface;
  */
 #define DHCP_EB_SIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 3 )
 
+/** MAC address
+ *
+ * This option is used internally to contain the network device
+ * hardware address, in order to provide a consistent approach to
+ * storing and processing options.  It should never be present in a
+ * DHCP packet.
+ */
+#define DHCP_EB_MAC DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 4 )
+
 /*
  * Tags in the range 0x10-0x7f are reserved for feature markers
  *
index 09ae64e..0b3b6c4 100644 (file)
 #define ERRFILE_dns                    ( ERRFILE_NET | 0x00110000 )
 #define ERRFILE_tftp                   ( ERRFILE_NET | 0x00120000 )
 #define ERRFILE_infiniband             ( ERRFILE_NET | 0x00130000 )
+#define ERRFILE_netdev_settings                ( ERRFILE_NET | 0x00140000 )
 
 #define ERRFILE_image                ( ERRFILE_IMAGE | 0x00000000 )
 #define ERRFILE_elf                  ( ERRFILE_IMAGE | 0x00010000 )
index 5d5e05b..6f5c06f 100644 (file)
@@ -11,6 +11,7 @@
 #include <gpxe/list.h>
 #include <gpxe/tables.h>
 #include <gpxe/refcnt.h>
+#include <gpxe/settings.h>
 
 struct io_buffer;
 struct net_device;
@@ -243,6 +244,9 @@ struct net_device {
        /** Device statistics */
        struct net_device_stats stats;
 
+       /** Configuration settings applicable to this device */
+       struct settings settings;
+
        /** Driver private data */
        void *priv;
 };
@@ -360,6 +364,8 @@ extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
 extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
                    uint16_t net_proto, const void *ll_source );
 
+extern struct settings_operations netdev_settings_operations;
+
 /**
  * Complete network transmission
  *
index d92cdb5..5333c4f 100644 (file)
@@ -17,7 +17,7 @@ struct in_addr;
 
 /** Settings block operations */
 struct settings_operations {
-       /** Set value of setting
+       /** Store value of setting
         *
         * @v settings          Settings block
         * @v tag               Setting tag number
diff --git a/src/net/netdev_settings.c b/src/net/netdev_settings.c
new file mode 100644 (file)
index 0000000..9baad88
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <gpxe/dhcp.h>
+#include <gpxe/settings.h>
+#include <gpxe/netdevice.h>
+
+/** @file
+ *
+ * Network device configuration settings
+ *
+ */
+
+/**
+ * Store value of network device setting
+ *
+ * @v settings         Settings block
+ * @v tag              Setting tag number
+ * @v data             Setting data, or NULL to clear setting
+ * @v len              Length of setting data
+ * @ret rc             Return status code
+ */
+static int netdev_store ( struct settings *settings, unsigned int tag,
+                         const void *data, size_t len ) {
+       struct net_device *netdev =
+               container_of ( settings, struct net_device, settings );
+
+       switch ( tag ) {
+       case DHCP_EB_MAC:
+               if ( len != netdev->ll_protocol->ll_addr_len )
+                       return -EINVAL;
+               memcpy ( netdev->ll_addr, data, len );
+               return 0;
+       default :
+               return simple_settings_store ( settings, tag, data, len );
+       }
+}
+
+/**
+ * Fetch value of network device setting
+ *
+ * @v settings         Settings block
+ * @v tag              Setting tag number
+ * @v data             Setting data, or NULL to clear setting
+ * @v len              Length of setting data
+ * @ret rc             Return status code
+ */
+static int netdev_fetch ( struct settings *settings, unsigned int tag,
+                         void *data, size_t len ) {
+       struct net_device *netdev =
+               container_of ( settings, struct net_device, settings );
+
+       switch ( tag ) {
+       case DHCP_EB_MAC:
+               if ( len > netdev->ll_protocol->ll_addr_len )
+                       len = netdev->ll_protocol->ll_addr_len;
+               memcpy ( data, netdev->ll_addr, len );
+               return netdev->ll_protocol->ll_addr_len;
+       default :
+               return simple_settings_fetch ( settings, tag, data, len );
+       }
+}
+
+/** Network device configuration settings operations */
+struct settings_operations netdev_settings_operations = {
+       .store = netdev_store,
+       .fetch = netdev_fetch,
+};
+
+/** Network device named settings */
+struct named_setting netdev_named_settings[] __named_setting = {
+       {
+               .name = "mac",
+               .description = "MAC address",
+               .tag = DHCP_EB_MAC,
+               .type = &setting_type_hex,
+       },
+};
index f2778e8..323e910 100644 (file)
@@ -266,6 +266,9 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
                netdev->refcnt.free = free_netdev;
                INIT_LIST_HEAD ( &netdev->tx_queue );
                INIT_LIST_HEAD ( &netdev->rx_queue );
+               settings_init ( &netdev->settings,
+                               &netdev_settings_operations, &netdev->refcnt,
+                               netdev->name );
                netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
        }
        return netdev;
@@ -282,11 +285,19 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
  */
 int register_netdev ( struct net_device *netdev ) {
        static unsigned int ifindex = 0;
+       int rc;
 
        /* Create device name */
        snprintf ( netdev->name, sizeof ( netdev->name ), "net%d",
                   ifindex++ );
 
+       /* Register per-netdev configuration settings */
+       if ( ( rc = register_settings ( &netdev->settings, NULL ) ) != 0 ) {
+               DBGC ( netdev, "NETDEV %p could not register settings: %s\n",
+                      netdev, strerror ( rc ) );
+               return rc;
+       }
+
        /* Add to device list */
        netdev_get ( netdev );
        list_add_tail ( &netdev->list, &net_devices );
@@ -357,6 +368,9 @@ void unregister_netdev ( struct net_device *netdev ) {
        /* Ensure device is closed */
        netdev_close ( netdev );
 
+       /* Unregister per-netdev configuration settings */
+       unregister_settings ( &netdev->settings );
+
        /* Remove from device list */
        list_del ( &netdev->list );
        netdev_put ( netdev );