]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[settings] Formalise notion of setting applicability
authorMichael Brown <mcb30@ipxe.org>
Tue, 22 Mar 2011 16:56:35 +0000 (16:56 +0000)
committerMichael Brown <mcb30@ipxe.org>
Tue, 22 Mar 2011 19:54:58 +0000 (19:54 +0000)
Expose a function setting_applies() to allow a caller to determine
whether or not a particular setting is applicable to a particular
settings block.

Restrict DHCP-backed settings blocks to accepting only DHCP-based
settings.

Restrict network device settings blocks to accepting only DHCP-based
settings and network device-specific settings such as "mac".

Inspired-by: Glenn Brown <glenn@myri.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
12 files changed:
src/core/nvo.c
src/core/settings.c
src/drivers/net/phantom/phantom.c
src/include/ipxe/dhcpopts.h
src/include/ipxe/net80211.h
src/include/ipxe/netdevice.h
src/include/ipxe/settings.h
src/interface/smbios/smbios_settings.c
src/net/80211/net80211.c
src/net/dhcpopts.c
src/net/dhcppkt.c
src/net/netdev_settings.c

index f4da407aa3900327de0e9da9c31be261fbd6c965..ea58badef3e837c560802aaccaff0e3dd2eae774 100644 (file)
@@ -184,6 +184,19 @@ static int nvo_save ( struct nvo_block *nvo ) {
        return 0;
 }
 
+/**
+ * Check applicability of NVO setting
+ *
+ * @v settings         Settings block
+ * @v setting          Setting
+ * @ret applies                Setting applies within this settings block
+ */
+static int nvo_applies ( struct settings *settings __unused,
+                        struct setting *setting ) {
+
+       return dhcpopt_applies ( setting->tag );
+}
+
 /**
  * Store value of NVO setting
  *
@@ -236,6 +249,7 @@ static int nvo_fetch ( struct settings *settings, struct setting *setting,
 
 /** NVO settings operations */
 static struct settings_operations nvo_settings_operations = {
+       .applies = nvo_applies,
        .store = nvo_store,
        .fetch = nvo_fetch,
 };
index 139addd52ff8636a74765fcfb52be780611e9370..a080904c54334863393895fefc4edca50e4a995b 100644 (file)
@@ -492,6 +492,19 @@ void unregister_settings ( struct settings *settings ) {
  ******************************************************************************
  */
 
+/**
+ * Check applicability of setting
+ *
+ * @v settings         Settings block
+ * @v setting          Setting
+ * @ret applies                Setting applies within this settings block
+ */
+int setting_applies ( struct settings *settings, struct setting *setting ) {
+
+       return ( settings->op->applies ?
+                settings->op->applies ( settings, setting ) : 1 );
+}
+
 /**
  * Store value of setting
  *
@@ -509,6 +522,10 @@ int store_setting ( struct settings *settings, struct setting *setting,
        if ( ! settings )
                settings = &settings_root;
 
+       /* Fail if tag does not apply to this settings block */
+       if ( ! setting_applies ( settings, setting ) )
+               return -ENOTTY;
+
        /* Sanity check */
        if ( ! settings->op->store )
                return -ENOTSUP;
@@ -564,10 +581,12 @@ int fetch_setting ( struct settings *settings, struct setting *setting,
        if ( ! settings->op->fetch )
                return -ENOTSUP;
 
-       /* Try this block first */
-       if ( ( ret = settings->op->fetch ( settings, setting,
-                                          data, len ) ) >= 0 )
+       /* Try this block first, if applicable */
+       if ( setting_applies ( settings, setting ) &&
+            ( ( ret = settings->op->fetch ( settings, setting,
+                                            data, len ) ) >= 0 ) ) {
                return ret;
+       }
 
        /* Recurse into each child block in turn */
        list_for_each_entry ( child, &settings->children, siblings ) {
@@ -886,17 +905,19 @@ struct setting * find_setting ( const char *name ) {
 /**
  * Parse setting name as tag number
  *
+ * @v settings         Settings block
  * @v name             Name
  * @ret tag            Tag number, or 0 if not a valid number
  */
-static unsigned int parse_setting_tag ( const char *name ) {
+static unsigned int parse_setting_tag ( struct settings *settings,
+                                       const char *name ) {
        char *tmp = ( ( char * ) name );
        unsigned int tag = 0;
 
        while ( 1 ) {
                tag = ( ( tag << 8 ) | strtoul ( tmp, &tmp, 0 ) );
                if ( *tmp == 0 )
-                       return tag;
+                       return ( tag | settings->tag_magic );
                if ( *tmp != '.' )
                        return 0;
                tmp++;
@@ -946,6 +967,7 @@ parse_setting_name ( const char *name,
        char *setting_name;
        char *type_name;
        struct setting *named_setting;
+       unsigned int tag;
 
        /* Set defaults */
        *settings = &settings_root;
@@ -979,9 +1001,10 @@ parse_setting_name ( const char *name,
        if ( ( named_setting = find_setting ( setting_name ) ) != NULL ) {
                /* Matches a defined named setting; use that setting */
                memcpy ( setting, named_setting, sizeof ( *setting ) );
-       } else if ( ( setting->tag = parse_setting_tag ( setting_name ) ) !=0){
+       } else if ( ( tag = parse_setting_tag ( *settings,
+                                               setting_name ) ) != 0 ) {
                /* Is a valid numeric tag; use the tag */
-               setting->tag |= (*settings)->tag_magic;
+               setting->tag = tag;
        } else {
                /* Use the arbitrary name */
                setting->name = setting_name;
index 1060103c7546d3e28b69da9ab62de15f215e2306..a55319ea67a7083fb6f57d2af2c53bc404fbe989 100644 (file)
@@ -1697,6 +1697,24 @@ phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) {
        return 0;
 }
 
+/**
+ * Check applicability of Phantom CLP setting
+ *
+ * @v settings         Settings block
+ * @v setting          Setting
+ * @ret applies                Setting applies within this settings block
+ */
+static int phantom_setting_applies ( struct settings *settings,
+                                    struct setting *setting ) {
+       struct phantom_nic *phantom =
+               container_of ( settings, struct phantom_nic, settings );
+       unsigned int clp_setting;
+
+       /* Find Phantom setting equivalent to iPXE setting */
+       clp_setting = phantom_clp_setting ( phantom, setting );
+       return ( clp_setting != 0 );
+}
+
 /**
  * Store Phantom CLP setting
  *
@@ -1716,8 +1734,7 @@ static int phantom_store_setting ( struct settings *settings,
 
        /* Find Phantom setting equivalent to iPXE setting */
        clp_setting = phantom_clp_setting ( phantom, setting );
-       if ( ! clp_setting )
-               return -ENOTSUP;
+       assert ( clp_setting != 0 );
 
        /* Store setting */
        if ( ( rc = phantom_clp_store ( phantom, phantom->port,
@@ -1750,8 +1767,7 @@ static int phantom_fetch_setting ( struct settings *settings,
 
        /* Find Phantom setting equivalent to iPXE setting */
        clp_setting = phantom_clp_setting ( phantom, setting );
-       if ( ! clp_setting )
-               return -ENOTSUP;
+       assert ( clp_setting != 0 );
 
        /* Fetch setting */
        if ( ( read_len = phantom_clp_fetch ( phantom, phantom->port,
@@ -1767,6 +1783,7 @@ static int phantom_fetch_setting ( struct settings *settings,
 
 /** Phantom CLP settings operations */
 static struct settings_operations phantom_settings_operations = {
+       .applies        = phantom_setting_applies,
        .store          = phantom_store_setting,
        .fetch          = phantom_fetch_setting,
 };
index 8fb3d2d79a3e17d67d806fadd36544a5e42a2cff..c5af5d74944421756c8e7853d61b5582429dbfdc 100644 (file)
@@ -28,6 +28,7 @@ struct dhcp_options {
        int ( * realloc ) ( struct dhcp_options *options, size_t len );
 };
 
+extern int dhcpopt_applies ( unsigned int tag );
 extern int dhcpopt_store ( struct dhcp_options *options, unsigned int tag,
                           const void *data, size_t len );
 extern int dhcpopt_fetch ( struct dhcp_options *options, unsigned int tag,
index d70eb7cb876555423fbc2abb205cf5831a4a6579..ac844b40837b0d2f0050cea33b00387bf5169a0e 100644 (file)
@@ -1183,4 +1183,25 @@ static inline u16 net80211_cts_duration ( struct net80211_device *dev,
                 net80211_duration ( dev, size, dev->rates[dev->rate] ) );
 }
 
+/** 802.11 device setting tag magic */
+#define NET80211_SETTING_TAG_MAGIC 0x8211
+
+/**
+ * Construct 802.11 setting tag
+ *
+ * @v id               Unique identifier
+ * @ret tag            Setting tag
+ */
+#define NET80211_SETTING_TAG( id ) \
+       NETDEV_SETTING_TAG ( ( NET80211_SETTING_TAG_MAGIC << 8 ) | (id) )
+
+/** SSID setting tag */
+#define NET80211_SETTING_TAG_SSID NET80211_SETTING_TAG ( 0x01 )
+
+/** Active scanning setting tag */
+#define NET80211_SETTING_TAG_ACTIVE_SCAN NET80211_SETTING_TAG ( 0x02 )
+
+/** Wireless key setting tag */
+#define NET80211_SETTING_TAG_KEY NET80211_SETTING_TAG ( 0x03 )
+
 #endif
index ac7cec521795fe92d3f690e93545e7a949e1e179..e49191f4ae214268cb59246e2b1365d3c9f4e142 100644 (file)
@@ -390,6 +390,38 @@ struct net_driver {
 /** Declare a network driver */
 #define __net_driver __table_entry ( NET_DRIVERS, 01 )
 
+/** Network device setting tag magic
+ *
+ * All DHCP option settings are deemed to be valid as network device
+ * settings.  There are also some extra non-DHCP settings (such as
+ * "mac"), which are marked as being valid network device settings by
+ * using a magic tag value.
+ */
+#define NETDEV_SETTING_TAG_MAGIC 0xeb
+
+/**
+ * Construct network device setting tag
+ *
+ * @v id               Unique identifier
+ * @ret tag            Setting tag
+ */
+#define NETDEV_SETTING_TAG( id ) ( ( NETDEV_SETTING_TAG_MAGIC << 24 ) | (id) )
+
+/**
+ * Check if tag is a network device setting tag
+ *
+ * @v tag              Setting tag
+ * @ret is_ours                Tag is a network device setting tag
+ */
+#define IS_NETDEV_SETTING_TAG( tag ) \
+       ( ( (tag) >> 24 ) == NETDEV_SETTING_TAG_MAGIC )
+
+/** MAC address setting tag */
+#define NETDEV_SETTING_TAG_MAC NETDEV_SETTING_TAG ( 0x01 )
+
+/** Bus ID setting tag */
+#define NETDEV_SETTING_TAG_BUS_ID NETDEV_SETTING_TAG ( 0x02 )
+
 extern struct list_head net_devices;
 extern struct net_device_operations null_netdev_operations;
 extern struct settings_operations netdev_settings_operations;
index d99e5ec0b611eaafd58458cd9293c3d5609f8cf6..b2b63f8ad1f068d8aeca752b1f63102e86802994 100644 (file)
@@ -33,7 +33,31 @@ struct setting {
         * address, etc.).
         */
        struct setting_type *type;
-       /** DHCP option number, if applicable */
+       /** Setting tag, if applicable
+        *
+        * The setting tag is a numerical description of the setting
+        * (such as a DHCP option number, or an SMBIOS structure and
+        * field number).
+        *
+        * Users can construct tags for settings that are not
+        * explicitly known to iPXE using the generic syntax for
+        * numerical settings.  For example, the setting name "60"
+        * will be interpreted as referring to DHCP option 60 (the
+        * vendor class identifier).
+        *
+        * This creates a potential for namespace collisions, since
+        * the interpretation of the numerical description will vary
+        * according to the settings block.  When a user attempts to
+        * fetch a generic numerical setting, we need to ensure that
+        * only the intended settings block interprets the numerical
+        * description.  (For example, we do not want to attempt to
+        * retrieve the subnet mask from SMBIOS, or the system UUID
+        * from DHCP.)
+        *
+        * This potential problem is resolved by allowing the setting
+        * tag to include a "magic" value indicating the
+        * interpretation to be placed upon the numerical description.
+        */
        unsigned int tag;
 };
 
@@ -45,6 +69,14 @@ struct setting {
 
 /** Settings block operations */
 struct settings_operations {
+       /** Check applicability of setting
+        *
+        * @v settings          Settings block
+        * @v setting           Setting
+        * @ret applies         Setting applies within this settings block
+        */
+       int ( * applies ) ( struct settings *settings,
+                           struct setting *setting );
        /** Store value of setting
         *
         * @v settings          Settings block
@@ -84,9 +116,7 @@ struct settings {
        /** Tag magic
         *
         * This value will be ORed in to any numerical tags
-        * constructed by parse_setting_name(), and can be used to
-        * avoid e.g. attempting to retrieve the subnet mask from
-        * SMBIOS, or the system UUID from DHCP.
+        * constructed by parse_setting_name().
         */
        unsigned int tag_magic;
        /** Parent settings block */
@@ -181,6 +211,8 @@ extern int register_settings ( struct settings *settings,
                               struct settings *parent, const char *name );
 extern void unregister_settings ( struct settings *settings );
 
+extern int setting_applies ( struct settings *settings,
+                            struct setting *setting );
 extern int store_setting ( struct settings *settings, struct setting *setting,
                           const void *data, size_t len );
 extern int fetch_setting ( struct settings *settings, struct setting *setting,
index bb7c18dd8c9f65d9f7d6857428f75745f2af7f14..6594c94b605f1847df09457fb85685c3e7d233b9 100644 (file)
@@ -63,6 +63,22 @@ FILE_LICENCE ( GPL2_OR_LATER );
          ( (_type) << 16 ) |                                   \
          ( offsetof ( _structure, _field ) << 8 ) )
 
+/**
+ * Check applicability of SMBIOS setting
+ *
+ * @v settings         Settings block
+ * @v setting          Setting
+ * @ret applies                Setting applies within this settings block
+ */
+static int smbios_applies ( struct settings *settings __unused,
+                           struct setting *setting ) {
+       unsigned int tag_magic;
+
+       /* Check tag magic */
+       tag_magic = ( setting->tag >> 24 );
+       return ( tag_magic == SMBIOS_TAG_MAGIC );
+}
+
 /**
  * Fetch value of SMBIOS setting
  *
@@ -87,8 +103,7 @@ static int smbios_fetch ( struct settings *settings __unused,
        tag_type = ( ( setting->tag >> 16 ) & 0xff );
        tag_offset = ( ( setting->tag >> 8 ) & 0xff );
        tag_len = ( setting->tag & 0xff );
-       if ( tag_magic != SMBIOS_TAG_MAGIC )
-               return -ENOENT;
+       assert ( tag_magic == SMBIOS_TAG_MAGIC );
 
        /* Find SMBIOS structure */
        if ( ( rc = find_smbios_structure ( tag_type, &structure ) ) != 0 )
@@ -119,6 +134,7 @@ static int smbios_fetch ( struct settings *settings __unused,
 
 /** SMBIOS settings operations */
 static struct settings_operations smbios_settings_operations = {
+       .applies = smbios_applies,
        .fetch = smbios_fetch,
 };
 
index d39958ba7d90eb94390c6ab3ed71062cefff1157..c42928e8a8421bfb6b686e60f12f48f1cf70b511 100644 (file)
@@ -206,6 +206,7 @@ struct setting net80211_ssid_setting __setting = {
        .name = "ssid",
        .description = "802.11 SSID (network name)",
        .type = &setting_type_string,
+       .tag = NET80211_SETTING_TAG_SSID,
 };
 
 /** Whether to use active scanning
@@ -218,6 +219,7 @@ struct setting net80211_active_setting __setting = {
        .name = "active-scan",
        .description = "Use an active scan during 802.11 association",
        .type = &setting_type_int8,
+       .tag = NET80211_SETTING_TAG_ACTIVE_SCAN,
 };
 
 /** The cryptographic key to use
@@ -230,6 +232,7 @@ struct setting net80211_key_setting __setting = {
        .name = "key",
        .description = "Encryption key for protected 802.11 networks",
        .type = &setting_type_string,
+       .tag = NET80211_SETTING_TAG_KEY,
 };
 
 /** @} */
index f04b8e712e1298575ca964a0068a888f1ad139d4..249fde151bc2fc10bb6458af9bc04075d245c5bd 100644 (file)
@@ -347,6 +347,18 @@ static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
        return offset;
 }
 
+/**
+ * Check applicability of DHCP option setting
+ *
+ * @v tag              Setting tag number
+ * @ret applies                Setting applies to this option block
+ */
+int dhcpopt_applies ( unsigned int tag ) {
+
+       return ( tag && ( tag <= DHCP_ENCAP_OPT ( DHCP_MAX_OPTION,
+                                                 DHCP_MAX_OPTION ) ) );
+}
+
 /**
  * Store value of DHCP option setting
  *
index 237c3e2cf609b1da3e5ebcae29257d16e85d9133..0a0e458fceb602ad9ac7f97502a0d32b6dc256ec 100644 (file)
@@ -134,6 +134,19 @@ find_dhcp_packet_field ( unsigned int tag ) {
        return NULL;
 }
 
+/**
+ * Check applicability of DHCP setting
+ *
+ * @v dhcppkt          DHCP packet
+ * @v tag              Setting tag number
+ * @ret applies                Setting applies within this settings block
+ */
+static int dhcppkt_applies ( struct dhcp_packet *dhcppkt __unused,
+                            unsigned int tag ) {
+
+       return dhcpopt_applies ( tag );
+}
+
 /**
  * Store value of DHCP packet setting
  *
@@ -204,6 +217,21 @@ int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
  *
  */
 
+/**
+ * Check applicability of DHCP setting
+ *
+ * @v settings         Settings block
+ * @v setting          Setting
+ * @ret applies                Setting applies within this settings block
+ */
+static int dhcppkt_settings_applies ( struct settings *settings,
+                                     struct setting *setting ) {
+       struct dhcp_packet *dhcppkt =
+               container_of ( settings, struct dhcp_packet, settings );
+
+       return dhcppkt_applies ( dhcppkt, setting->tag );
+}
+
 /**
  * Store value of DHCP setting
  *
@@ -242,6 +270,7 @@ static int dhcppkt_settings_fetch ( struct settings *settings,
 
 /** DHCP settings operations */
 static struct settings_operations dhcppkt_settings_operations = {
+       .applies = dhcppkt_settings_applies,
        .store = dhcppkt_settings_store,
        .fetch = dhcppkt_settings_fetch,
 };
index f641d3b217c64a548f22ee3bbf765e3f193ebf6f..2ff4ad3e3053d71d1ab38d0bc2a2bdf36863d21f 100644 (file)
@@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <errno.h>
 #include <byteswap.h>
 #include <ipxe/dhcp.h>
+#include <ipxe/dhcpopts.h>
 #include <ipxe/settings.h>
 #include <ipxe/device.h>
 #include <ipxe/netdevice.h>
@@ -37,13 +38,29 @@ struct setting mac_setting __setting = {
        .name = "mac",
        .description = "MAC address",
        .type = &setting_type_hex,
+       .tag = NETDEV_SETTING_TAG_MAC,
 };
 struct setting busid_setting __setting = {
        .name = "busid",
        .description = "Bus ID",
        .type = &setting_type_hex,
+       .tag = NETDEV_SETTING_TAG_BUS_ID,
 };
 
+/**
+ * Check applicability of network device setting
+ *
+ * @v settings         Settings block
+ * @v setting          Setting
+ * @ret applies                Setting applies within this settings block
+ */
+static int netdev_applies ( struct settings *settings __unused,
+                           struct setting *setting ) {
+
+       return ( IS_NETDEV_SETTING_TAG ( setting->tag ) ||
+                dhcpopt_applies ( setting->tag ) );
+}
+
 /**
  * Store value of network device setting
  *
@@ -114,6 +131,7 @@ static void netdev_clear ( struct settings *settings ) {
 
 /** Network device configuration settings operations */
 struct settings_operations netdev_settings_operations = {
+       .applies = netdev_applies,
        .store = netdev_store,
        .fetch = netdev_fetch,
        .clear = netdev_clear,