[settings] Formalise notion of setting applicability

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>
pull/1/head
Michael Brown 2011-03-22 16:56:35 +00:00
parent 9215b7f4c0
commit f5fd4dec3b
12 changed files with 235 additions and 17 deletions

View 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,
};

View 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;

View 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,
};

View 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,

View 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

View 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;

View 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,

View 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,
};

View 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,
};
/** @} */

View 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
*

View 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,
};

View 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,