From cf033046206aede5064c798bfa887fbb888b9217 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 20 Mar 2008 23:15:48 +0000 Subject: [PATCH] [Settings] Introduce settings applicators. Convert DHCP option applicators in dns.c and iscsi.c to settings applicators. Kill off DHCP option applicators. --- src/core/settings.c | 111 +++++++++++++++++++++++++--- src/include/gpxe/dhcp.h | 17 ----- src/include/gpxe/settings.h | 32 ++++---- src/net/dhcpopts.c | 24 ------ src/net/tcp/iscsi.c | 141 ++++++++++++++++++++++-------------- src/net/udp/dns.c | 33 ++++----- 6 files changed, 221 insertions(+), 137 deletions(-) diff --git a/src/core/settings.c b/src/core/settings.c index 49a7410d..458ba111 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -37,15 +37,21 @@ /** Registered setting types */ static struct setting_type setting_types[0] -__table_start ( struct setting_type, setting_types ); + __table_start ( struct setting_type, setting_types ); static struct setting_type setting_types_end[0] -__table_end ( struct setting_type, setting_types ); + __table_end ( struct setting_type, setting_types ); /** Registered named settings */ static struct named_setting named_settings[0] -__table_start ( struct named_setting, named_settings ); + __table_start ( struct named_setting, named_settings ); static struct named_setting named_settings_end[0] -__table_end ( struct named_setting, named_settings ); + __table_end ( struct named_setting, named_settings ); + +/** Registered settings applicators */ +static struct settings_applicator settings_applicators[0] + __table_start ( struct settings_applicator, settings_applicators ); +static struct settings_applicator settings_applicators_end[0] + __table_end ( struct settings_applicator, settings_applicators ); /** * Obtain printable version of a settings tag number @@ -94,10 +100,6 @@ int simple_settings_fetch ( struct settings *settings, unsigned int tag, return ( len ? len : 8 ); } -// Dummy routine just for testing -static void apply_settings ( void ) { -} - /** Simple settings operations */ struct settings_operations simple_settings_operations = { .store = simple_settings_store, @@ -113,6 +115,66 @@ struct settings settings_root = { .op = &simple_settings_operations, }; +/** + * Apply all settings + * + * @ret rc Return status code + */ +static int apply_settings ( void ) { + struct settings_applicator *applicator; + int rc; + + /* Call all settings applicators */ + for ( applicator = settings_applicators ; + applicator < settings_applicators_end ; applicator++ ) { + if ( ( rc = applicator->apply() ) != 0 ) { + DBG ( "Could not apply settings using applicator " + "%p: %s\n", applicator, strerror ( rc ) ); + return rc; + } + } + + return 0; +} + +/** + * Reprioritise settings + * + * @v settings Settings block + * + * Reorders the settings block amongst its siblings according to its + * priority. + */ +static void reprioritise_settings ( struct settings *settings ) { + struct settings *parent = settings->parent; + long priority; + struct settings *tmp; + long tmp_priority; + + /* Stop when we reach the top of the tree */ + if ( ! parent ) + return; + + /* Read priority, if present */ + priority = 0; + fetch_int_setting ( settings, DHCP_EB_PRIORITY, &priority ); + + /* Remove from siblings list */ + list_del ( &settings->siblings ); + + /* Reinsert after any existing blocks which have a higher priority */ + list_for_each_entry ( tmp, &parent->children, siblings ) { + tmp_priority = 0; + fetch_int_setting ( tmp, DHCP_EB_PRIORITY, &tmp_priority ); + if ( priority > tmp_priority ) + break; + } + list_add_tail ( &settings->siblings, &tmp->siblings ); + + /* Recurse up the tree */ + reprioritise_settings ( parent ); +} + /** * Register settings block * @@ -134,6 +196,9 @@ int register_settings ( struct settings *settings, struct settings *parent ) { list_add_tail ( &settings->siblings, &parent->children ); DBGC ( settings, "Settings %p registered\n", settings ); + /* Fix up settings priority */ + reprioritise_settings ( settings ); + /* Apply potentially-updated settings */ apply_settings(); @@ -206,6 +271,34 @@ struct settings * find_settings ( const char *name ) { ****************************************************************************** */ +/** + * Store value of 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 + */ +int store_setting ( struct settings *settings, unsigned int tag, + const void *data, size_t len ) { + int rc; + + /* Store setting */ + if ( ( rc = settings->op->store ( settings, tag, data, len ) ) != 0 ) + return rc; + + /* Reprioritise settings if necessary */ + if ( tag == DHCP_EB_PRIORITY ) + reprioritise_settings ( settings ); + + /* Apply potentially-updated setting */ + if ( ( rc = apply_settings() ) != 0 ) + return rc; + + return 0; +} + /** * Fetch value of setting * @@ -288,7 +381,7 @@ int fetch_ipv4_setting ( struct settings *settings, unsigned int tag, len = fetch_setting ( settings, tag, inp, sizeof ( *inp ) ); if ( len < 0 ) return len; - if ( len != sizeof ( *inp ) ) + if ( len < ( int ) sizeof ( *inp ) ) return -ERANGE; return len; } diff --git a/src/include/gpxe/dhcp.h b/src/include/gpxe/dhcp.h index 3da96525..a8fa811f 100644 --- a/src/include/gpxe/dhcp.h +++ b/src/include/gpxe/dhcp.h @@ -489,23 +489,6 @@ struct dhcp_packet { struct dhcp_option_block options; }; -/** A DHCP option applicator */ -struct dhcp_option_applicator { - /** DHCP option tag */ - unsigned int tag; - /** Applicator - * - * @v tag DHCP option tag - * @v option DHCP option - * @ret rc Return status code - */ - int ( * apply ) ( unsigned int tag, struct dhcp_option *option ); -}; - -/** Declare a DHCP option applicator */ -#define __dhcp_applicator \ - __table ( struct dhcp_option_applicator, dhcp_applicators, 01 ) - /** * Get reference to DHCP options block * diff --git a/src/include/gpxe/settings.h b/src/include/gpxe/settings.h index 5333c4f2..94ca9e0f 100644 --- a/src/include/gpxe/settings.h +++ b/src/include/gpxe/settings.h @@ -122,6 +122,22 @@ struct named_setting { /** Declare a configuration setting */ #define __named_setting __table ( struct named_setting, named_settings, 01 ) +/** + * A settings applicator + * + */ +struct settings_applicator { + /** Apply updated settings + * + * @ret rc Return status code + */ + int ( * apply ) ( void ); +}; + +/** Declare a settings applicator */ +#define __settings_applicator \ + __table ( struct settings_applicator, settings_applicators, 01 ) + extern int simple_settings_store ( struct settings *settings, unsigned int tag, const void *data, size_t len ); extern int simple_settings_fetch ( struct settings *settings, unsigned int tag, @@ -131,6 +147,8 @@ extern struct settings_operations simple_settings_operations; extern int register_settings ( struct settings *settings, struct settings *parent ); extern void unregister_settings ( struct settings *settings ); +extern int store_setting ( struct settings *settings, unsigned int tag, + const void *data, size_t len ); extern int fetch_setting ( struct settings *settings, unsigned int tag, void *data, size_t len ); extern int fetch_setting_len ( struct settings *settings, unsigned int tag ); @@ -179,20 +197,6 @@ static inline void settings_init ( struct settings *settings, settings->name = name; } -/** - * Store value of 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 inline int store_setting ( struct settings *settings, unsigned int tag, - const void *data, size_t len ) { - return settings->op->store ( settings, tag, data, len ); -} - /** * Delete setting * diff --git a/src/net/dhcpopts.c b/src/net/dhcpopts.c index ed53916c..75a9f2a5 100644 --- a/src/net/dhcpopts.c +++ b/src/net/dhcpopts.c @@ -37,12 +37,6 @@ /** List of registered DHCP option blocks */ LIST_HEAD ( dhcp_option_blocks ); -/** Registered DHCP option applicators */ -static struct dhcp_option_applicator dhcp_option_applicators[0] - __table_start ( struct dhcp_option_applicator, dhcp_applicators ); -static struct dhcp_option_applicator dhcp_option_applicators_end[0] - __table_end ( struct dhcp_option_applicator, dhcp_applicators ); - /** * Obtain printable version of a DHCP option tag * @@ -578,13 +572,9 @@ void delete_dhcp_option ( struct dhcp_option_block *options, * @ret rc Return status code */ int apply_dhcp_options ( struct dhcp_option_block *options ) { - struct dhcp_option_applicator *applicator; - struct dhcp_option *option; struct in_addr tftp_server; struct uri *uri; char uri_string[32]; - unsigned int tag; - int rc; /* Set current working URI based on TFTP server */ find_dhcp_ipv4_option ( options, DHCP_EB_SIADDR, &tftp_server ); @@ -596,20 +586,6 @@ int apply_dhcp_options ( struct dhcp_option_block *options ) { churi ( uri ); uri_put ( uri ); - /* Call all registered DHCP option applicators */ - for ( applicator = dhcp_option_applicators ; - applicator < dhcp_option_applicators_end ; applicator++ ) { - tag = applicator->tag; - option = find_dhcp_option ( options, tag ); - if ( ! option ) - continue; - if ( ( rc = applicator->apply ( tag, option ) ) != 0 ) { - DBG ( "Could not apply DHCP option %s: %s\n", - dhcp_tag_name ( tag ), strerror ( rc ) ); - return rc; - } - } - return 0; } diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index cf6c7f5f..0e7b2582 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include @@ -1591,80 +1591,109 @@ int iscsi_attach ( struct scsi_device *scsi, const char *root_path ) { /**************************************************************************** * - * DHCP option applicators + * Settings applicators * */ -/** - * Apply DHCP iSCSI option - * - * @v tag DHCP option tag - * @v option DHCP option - * @ret rc Return status code - */ -static int apply_dhcp_iscsi_string ( unsigned int tag, - struct dhcp_option *option ) { - char *prefix = ""; - size_t prefix_len; - size_t len; +/** An iSCSI string setting */ +struct iscsi_string_setting { + /** Setting tag number */ + unsigned int tag; + /** String to update */ char **string; - char *p; + /** String prefix */ + const char *prefix; +}; - /* Identify string and prefix */ - switch ( tag ) { - case DHCP_ISCSI_INITIATOR_IQN: - string = &iscsi_explicit_initiator_iqn; - break; - case DHCP_EB_USERNAME: - string = &iscsi_username; - break; - case DHCP_EB_PASSWORD: - string = &iscsi_password; - break; - case DHCP_HOST_NAME: - string = &iscsi_default_initiator_iqn; - prefix = "iqn.2000-09.org.etherboot:"; - break; - default: - assert ( 0 ); - return -EINVAL; - } - - /* Free old string */ - free ( *string ); - *string = NULL; - - /* Allocate and fill new string */ - prefix_len = strlen ( prefix ); - len = ( prefix_len + option->len + 1 ); - p = *string = malloc ( len ); - if ( ! p ) - return -ENOMEM; - strcpy ( p, prefix ); - dhcp_snprintf ( ( p + prefix_len ), ( len - prefix_len ), option ); - return 0; -} - -/** DHCP iSCSI option applicators */ -struct dhcp_option_applicator dhcp_iscsi_applicators[] __dhcp_applicator = { +/** iSCSI string settings */ +static struct iscsi_string_setting iscsi_string_settings[] = { { .tag = DHCP_ISCSI_INITIATOR_IQN, - .apply = apply_dhcp_iscsi_string, + .string = &iscsi_explicit_initiator_iqn, + .prefix = "", }, { .tag = DHCP_EB_USERNAME, - .apply = apply_dhcp_iscsi_string, + .string = &iscsi_username, + .prefix = "", }, { .tag = DHCP_EB_PASSWORD, - .apply = apply_dhcp_iscsi_string, + .string = &iscsi_password, + .prefix = "", }, { .tag = DHCP_HOST_NAME, - .apply = apply_dhcp_iscsi_string, + .string = &iscsi_default_initiator_iqn, + .prefix = "iqn.2000-09.org.etherboot:", }, }; +/** + * Apply iSCSI setting + * + * @v setting iSCSI string setting + * @ret rc Return status code + */ +static int apply_iscsi_string_setting ( struct iscsi_string_setting *setting ){ + size_t prefix_len; + int setting_len; + size_t len; + int check_len; + char *p; + + /* Free old string */ + free ( *setting->string ); + *setting->string = NULL; + + /* Allocate new string */ + prefix_len = strlen ( setting->prefix ); + setting_len = fetch_setting_len ( NULL, setting->tag ); + if ( setting_len < 0 ) + return setting_len; + len = ( prefix_len + setting_len + 1 ); + p = *setting->string = malloc ( len ); + if ( ! p ) + return -ENOMEM; + + /* Fill new string */ + strcpy ( p, setting->prefix ); + check_len = fetch_string_setting ( NULL, setting->tag, + ( p + prefix_len ), + ( len - prefix_len ) ); + assert ( check_len == setting_len ); + + return 0; +} + +/** + * Apply iSCSI settings + * + * @ret rc Return status code + */ +static int apply_iscsi_settings ( void ) { + struct iscsi_string_setting *setting; + unsigned int i; + int rc; + + for ( i = 0 ; i < ( sizeof ( iscsi_string_settings ) / + sizeof ( iscsi_string_settings[0] ) ) ; i++ ) { + setting = &iscsi_string_settings[i]; + if ( ( rc = apply_iscsi_string_setting ( setting ) ) != 0 ) { + DBG ( "iSCSI could not apply setting %d\n", + setting->tag ); + return rc; + } + } + + return 0; +} + +/** iSCSI settings applicator */ +struct settings_applicator iscsi_settings_applicator __settings_applicator = { + .apply = apply_iscsi_settings, +}; + /**************************************************************************** * * Initiator name diff --git a/src/net/udp/dns.c b/src/net/udp/dns.c index d82d124b..5e632d18 100644 --- a/src/net/udp/dns.c +++ b/src/net/udp/dns.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include @@ -507,27 +507,26 @@ struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = { }; /** - * Apply DHCP nameserver option + * Apply nameserver setting * - * @v tag DHCP option tag - * @v option DHCP option + * @ret rc Return status code */ -static int apply_dhcp_nameserver ( unsigned int tag __unused, - struct dhcp_option *option ) { - struct sockaddr_in *sin_nameserver; +static int apply_nameserver_setting ( void ) { + struct sockaddr_in *sin_nameserver = + ( struct sockaddr_in * ) &nameserver; + int len; - sin_nameserver = ( struct sockaddr_in * ) &nameserver; - sin_nameserver->sin_family = AF_INET; - dhcp_ipv4_option ( option, &sin_nameserver->sin_addr ); - - DBG ( "DNS using nameserver %s\n", - inet_ntoa ( sin_nameserver->sin_addr ) ); + if ( ( len = fetch_ipv4_setting ( NULL, DHCP_DNS_SERVERS, + &sin_nameserver->sin_addr ) ) >= 0 ){ + sin_nameserver->sin_family = AF_INET; + DBG ( "DNS using nameserver %s\n", + inet_ntoa ( sin_nameserver->sin_addr ) ); + } return 0; } -/** DHCP nameserver applicator */ -struct dhcp_option_applicator dhcp_nameserver_applicator __dhcp_applicator = { - .tag = DHCP_DNS_SERVERS, - .apply = apply_dhcp_nameserver, +/** Nameserver setting applicator */ +struct settings_applicator nameserver_applicator __settings_applicator = { + .apply = apply_nameserver_setting, };