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
*
/** NVO settings operations */
static struct settings_operations nvo_settings_operations = {
+ .applies = nvo_applies,
.store = nvo_store,
.fetch = nvo_fetch,
};
******************************************************************************
*/
+/**
+ * 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
*
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;
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 ) {
/**
* 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++;
char *setting_name;
char *type_name;
struct setting *named_setting;
+ unsigned int tag;
/* Set defaults */
*settings = &settings_root;
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;
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
*
/* 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,
/* 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,
/** Phantom CLP settings operations */
static struct settings_operations phantom_settings_operations = {
+ .applies = phantom_setting_applies,
.store = phantom_store_setting,
.fetch = phantom_fetch_setting,
};
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,
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
/** 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;
* 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;
};
/** 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
/** 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 */
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,
( (_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
*
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 )
/** SMBIOS settings operations */
static struct settings_operations smbios_settings_operations = {
+ .applies = smbios_applies,
.fetch = smbios_fetch,
};
.name = "ssid",
.description = "802.11 SSID (network name)",
.type = &setting_type_string,
+ .tag = NET80211_SETTING_TAG_SSID,
};
/** Whether to use active scanning
.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
.name = "key",
.description = "Encryption key for protected 802.11 networks",
.type = &setting_type_string,
+ .tag = NET80211_SETTING_TAG_KEY,
};
/** @} */
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
*
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
*
*
*/
+/**
+ * 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
*
/** DHCP settings operations */
static struct settings_operations dhcppkt_settings_operations = {
+ .applies = dhcppkt_settings_applies,
.store = dhcppkt_settings_store,
.fetch = dhcppkt_settings_fetch,
};
#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>
.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
*
/** Network device configuration settings operations */
struct settings_operations netdev_settings_operations = {
+ .applies = netdev_applies,
.store = netdev_store,
.fetch = netdev_fetch,
.clear = netdev_clear,