[Settings] Remove assumption that all settings have DHCP tag values
authorMichael Brown <mcb30@etherboot.org>
Tue, 25 Mar 2008 20:46:16 +0000 (20:46 +0000)
committerMichael Brown <mcb30@etherboot.org>
Tue, 25 Mar 2008 20:46:16 +0000 (20:46 +0000)
Allow for settings to be described by something other than a DHCP option
tag if desirable.  Currently used only for the MAC address setting.

Separate out fake DHCP packet creation code from dhcp.c to fakedhcp.c.

Remove notion of settings from dhcppkt.c.

Rationalise dhcp.c to use settings API only for final registration of the
DHCP options, rather than using {store,fetch}_setting throughout.

24 files changed:
src/arch/i386/image/nbi.c
src/core/ibft.c
src/core/nvo.c
src/core/settings.c
src/hci/commands/nvo_cmd.c
src/hci/tui/settings_ui.c
src/include/gpxe/dhcp.h
src/include/gpxe/dhcpopts.h
src/include/gpxe/dhcppkt.h
src/include/gpxe/fakedhcp.h [new file with mode: 0644]
src/include/gpxe/settings.h
src/interface/pxe/pxe_preboot.c
src/net/dhcpopts.c
src/net/dhcppkt.c
src/net/fakedhcp.c [new file with mode: 0644]
src/net/ipv4.c
src/net/netdev_settings.c
src/net/tcp/iscsi.c
src/net/udp/dhcp.c
src/net/udp/dns.c
src/net/udp/tftp.c
src/usr/aoeboot.c
src/usr/autoboot.c
src/usr/iscsiboot.c

index 79dc8d1..73791be 100644 (file)
@@ -8,8 +8,7 @@
 #include <gpxe/segment.h>
 #include <gpxe/init.h>
 #include <gpxe/netdevice.h>
-#include <gpxe/dhcp.h>
-#include <gpxe/dhcppkt.h>
+#include <gpxe/fakedhcp.h>
 #include <gpxe/image.h>
 #include <gpxe/features.h>
 
@@ -400,8 +399,8 @@ static int nbi_prepare_dhcp ( struct image *image ) {
                return -ENODEV;
        }
 
-       if ( ( rc = create_dhcpack ( boot_netdev, basemem_packet,
-                                    sizeof ( basemem_packet ) ) ) != 0 ) {
+       if ( ( rc = create_fakedhcpack ( boot_netdev, basemem_packet,
+                                        sizeof ( basemem_packet ) ) ) != 0 ) {
                DBGC ( image, "NBI %p failed to build DHCP packet\n", image );
                return rc;
        }
index 61e00a8..fda1470 100644 (file)
@@ -123,15 +123,16 @@ static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) {
 }
 
 /**
- * Fill in an IP address within iBFT from DHCP option
+ * Fill in an IP address within iBFT from configuration setting
  *
  * @v ipaddr           IP address field
+ * @v setting          Configuration setting
  * @v tag              DHCP option tag
  */
 static void ibft_set_ipaddr_option ( struct ibft_ipaddr *ipaddr,
-                                    unsigned int tag ) {
+                                    struct setting *setting ) {
        struct in_addr in = { 0 };
-       fetch_ipv4_setting ( NULL, tag, &in );
+       fetch_ipv4_setting ( NULL, setting, &in );
        ibft_set_ipaddr ( ipaddr, in );
 }
 
@@ -182,21 +183,21 @@ static int ibft_set_string ( struct ibft_string_block *strings,
 }
 
 /**
- * Fill in a string field within iBFT from DHCP option
+ * Fill in a string field within iBFT from configuration setting
  *
  * @v strings          iBFT string block descriptor
  * @v string           String field
- * @v tag              DHCP option tag
+ * @v setting          Configuration setting
  * @ret rc             Return status code
  */
 static int ibft_set_string_option ( struct ibft_string_block *strings,
                                    struct ibft_string *string,
-                                   unsigned int tag ) {
+                                   struct setting *setting ) {
        int len;
        char *dest;
        int rc;
 
-       len = fetch_setting_len ( NULL, tag );
+       len = fetch_setting_len ( NULL, setting );
        if ( len < 0 ) {
                string->offset = 0;
                string->length = 0;
@@ -206,7 +207,7 @@ static int ibft_set_string_option ( struct ibft_string_block *strings,
        if ( ( rc = ibft_alloc_string ( strings, string, len ) ) != 0 )
                return rc;
        dest = ( ( ( char * ) strings->table ) + string->offset );
-       fetch_string_setting ( NULL, tag, dest, ( len + 1 ) );
+       fetch_string_setting ( NULL, setting, dest, ( len + 1 ) );
        return 0;
 }
 
@@ -226,15 +227,15 @@ static int ibft_fill_nic ( struct ibft_nic *nic,
        int rc;
 
        /* Extract values from DHCP configuration */
-       ibft_set_ipaddr_option ( &nic->ip_address, DHCP_EB_YIADDR );
-       ibft_set_ipaddr_option ( &nic->gateway, DHCP_ROUTERS );
-       ibft_set_ipaddr_option ( &nic->dns[0], DHCP_DNS_SERVERS );
+       ibft_set_ipaddr_option ( &nic->ip_address, &ip_setting );
+       ibft_set_ipaddr_option ( &nic->gateway, &gateway_setting );
+       ibft_set_ipaddr_option ( &nic->dns[0], &dns_setting );
        if ( ( rc = ibft_set_string_option ( strings, &nic->hostname,
-                                            DHCP_HOST_NAME ) ) != 0 )
+                                            &hostname_setting ) ) != 0 )
                return rc;
 
        /* Derive subnet mask prefix from subnet mask */
-       fetch_ipv4_setting ( NULL, DHCP_SUBNET_MASK, &netmask_addr );
+       fetch_ipv4_setting ( NULL, &netmask_setting, &netmask_addr );
        while ( netmask_addr.s_addr ) {
                if ( netmask_addr.s_addr & 0x1 )
                        netmask_count++;
index 951539f..1307802 100644 (file)
@@ -138,19 +138,20 @@ static void nvo_init_dhcpopts ( struct nvo_block *nvo ) {
  * Store value of NVO setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @v data             Setting data, or NULL to clear setting
  * @v len              Length of setting data
  * @ret rc             Return status code
  */
-static int nvo_store ( struct settings *settings, unsigned int tag,
+static int nvo_store ( struct settings *settings, struct setting *setting,
                       const void *data, size_t len ) {
        struct nvo_block *nvo =
                container_of ( settings, struct nvo_block, settings );
        int rc;
 
        /* Update stored options */
-       if ( ( rc = dhcpopt_store ( &nvo->dhcpopts, tag, data, len ) ) != 0 ) {
+       if ( ( rc = dhcpopt_store ( &nvo->dhcpopts, setting->tag,
+                                   data, len ) ) != 0 ) {
                DBGC ( nvo, "NVO %p could not store %zd bytes: %s\n",
                       nvo, len, strerror ( rc ) );
                return rc;
@@ -167,7 +168,7 @@ static int nvo_store ( struct settings *settings, unsigned int tag,
  * Fetch value of NVO setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v data             Buffer to fill with setting data
  * @v len              Length of buffer
  * @ret len            Length of setting data, or negative error
@@ -175,12 +176,12 @@ static int nvo_store ( struct settings *settings, unsigned int tag,
  * The actual length of the setting will be returned even if
  * the buffer was too small.
  */
-static int nvo_fetch ( struct settings *settings, unsigned int tag,
+static int nvo_fetch ( struct settings *settings, struct setting *setting,
                       void *data, size_t len ) {
        struct nvo_block *nvo =
                container_of ( settings, struct nvo_block, settings );
 
-       return dhcpopt_fetch ( &nvo->dhcpopts, tag, data, len );
+       return dhcpopt_fetch ( &nvo->dhcpopts, setting->tag, data, len );
 }
 
 /** NVO settings operations */
index 809779a..b793ae6 100644 (file)
  *
  */
 
+/** Registered settings */
+static struct setting settings[0]
+       __table_start ( struct setting, settings );
+static struct setting settings_end[0]
+       __table_end ( struct setting, settings );
+
 /** Registered setting types */
 static struct setting_type setting_types[0]
        __table_start ( struct setting_type, setting_types );
 static struct setting_type setting_types_end[0]
        __table_end ( struct setting_type, setting_types );
 
-/** Registered named settings */
-static struct named_setting named_settings[0]
-       __table_start ( struct named_setting, named_settings );
-static struct named_setting named_settings_end[0]
-       __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
- *
- * @v tag              Settings tag number
- * @ret name           String representation of the tag
- */
-static inline char * setting_tag_name ( unsigned int tag ) {
-       static char name[8];
-
-       if ( DHCP_IS_ENCAP_OPT ( tag ) ) {
-               snprintf ( name, sizeof ( name ), "%d.%d",
-                          DHCP_ENCAPSULATOR ( tag ),
-                          DHCP_ENCAPSULATED ( tag ) );
-       } else {
-               snprintf ( name, sizeof ( name ), "%d", tag );
-       }
-       return name;
-}
-
 /******************************************************************************
  *
  * Registered settings blocks
@@ -83,32 +64,33 @@ static inline char * setting_tag_name ( unsigned int tag ) {
  * Store value of simple setting
  *
  * @v options          DHCP option block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @v data             Setting data, or NULL to clear setting
  * @v len              Length of setting data
  * @ret rc             Return status code
  */
-int simple_settings_store ( struct settings *settings, unsigned int tag,
+int simple_settings_store ( struct settings *settings, struct setting *setting,
                            const void *data, size_t len ) {
        struct simple_settings *simple =
                container_of ( settings, struct simple_settings, settings );
-       return dhcpopt_extensible_store ( &simple->dhcpopts, tag, data, len );
+       return dhcpopt_extensible_store ( &simple->dhcpopts, setting->tag,
+                                         data, len );
 }
 
 /**
  * Fetch value of simple setting
  *
  * @v options          DHCP option block
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v data             Buffer to fill with setting data
  * @v len              Length of buffer
  * @ret len            Length of setting data, or negative error
  */
-int simple_settings_fetch ( struct settings *settings, unsigned int tag,
+int simple_settings_fetch ( struct settings *settings, struct setting *setting,
                            void *data, size_t len ) {
        struct simple_settings *simple =
                container_of ( settings, struct simple_settings, settings );
-       return dhcpopt_fetch ( &simple->dhcpopts, tag, data, len );
+       return dhcpopt_fetch ( &simple->dhcpopts, setting->tag, data, len );
 }
 
 /** Simple settings operations */
@@ -174,14 +156,14 @@ static void reprioritise_settings ( struct settings *settings ) {
                return;
 
        /* Read priority, if present */
-       priority = fetch_intz_setting ( settings, DHCP_EB_PRIORITY );
+       priority = fetch_intz_setting ( settings, &priority_setting );
 
        /* 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 = fetch_intz_setting ( tmp, DHCP_EB_PRIORITY );
+               tmp_priority = fetch_intz_setting ( tmp, &priority_setting );
                if ( priority > tmp_priority )
                        break;
        }
@@ -292,12 +274,12 @@ struct settings * find_settings ( const char *name ) {
  * Store value of setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @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,
+int store_setting ( struct settings *settings, struct setting *setting,
                    const void *data, size_t len ) {
        int rc;
 
@@ -306,11 +288,12 @@ int store_setting ( struct settings *settings, unsigned int tag,
                return -ENODEV;
 
        /* Store setting */
-       if ( ( rc = settings->op->store ( settings, tag, data, len ) ) != 0 )
+       if ( ( rc = settings->op->store ( settings, setting,
+                                         data, len ) ) != 0 )
                return rc;
 
        /* Reprioritise settings if necessary */
-       if ( tag == DHCP_EB_PRIORITY )
+       if ( setting_cmp ( setting, &priority_setting ) == 0 )
                reprioritise_settings ( settings );
 
        /* If these settings are registered, apply potentially-updated
@@ -331,7 +314,7 @@ int store_setting ( struct settings *settings, unsigned int tag,
  * Fetch value of setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v data             Buffer to fill with setting data
  * @v len              Length of buffer
  * @ret len            Length of setting data, or negative error
@@ -339,7 +322,7 @@ int store_setting ( struct settings *settings, unsigned int tag,
  * The actual length of the setting will be returned even if
  * the buffer was too small.
  */
-int fetch_setting ( struct settings *settings, unsigned int tag,
+int fetch_setting ( struct settings *settings, struct setting *setting,
                    void *data, size_t len ) {
        struct settings *child;
        int ret;
@@ -349,12 +332,14 @@ int fetch_setting ( struct settings *settings, unsigned int tag,
                settings = &settings_root;
 
        /* Try this block first */
-       if ( ( ret = settings->op->fetch ( settings, tag, data, len ) ) >= 0)
+       if ( ( 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 ) {
-               if ( ( ret = fetch_setting ( child, tag, data, len ) ) >= 0)
+               if ( ( ret = fetch_setting ( child, setting,
+                                            data, len ) ) >= 0 )
                        return ret;
        }
 
@@ -365,21 +350,21 @@ int fetch_setting ( struct settings *settings, unsigned int tag,
  * Fetch length of setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @ret len            Length of setting data, or negative error
  *
  * This function can also be used as an existence check for the
  * setting.
  */
-int fetch_setting_len ( struct settings *settings, unsigned int tag ) {
-       return fetch_setting ( settings, tag, NULL, 0 );
+int fetch_setting_len ( struct settings *settings, struct setting *setting ) {
+       return fetch_setting ( settings, setting, NULL, 0 );
 }
 
 /**
  * Fetch value of string setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v data             Buffer to fill with setting string data
  * @v len              Length of buffer
  * @ret len            Length of string setting, or negative error
@@ -388,25 +373,25 @@ int fetch_setting_len ( struct settings *settings, unsigned int tag ) {
  * The returned length will be the length of the underlying setting
  * data.
  */
-int fetch_string_setting ( struct settings *settings, unsigned int tag,
+int fetch_string_setting ( struct settings *settings, struct setting *setting,
                           char *data, size_t len ) {
        memset ( data, 0, len );
-       return fetch_setting ( settings, tag, data, ( len - 1 ) );
+       return fetch_setting ( settings, setting, data, ( len - 1 ) );
 }
 
 /**
  * Fetch value of IPv4 address setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v inp              IPv4 address to fill in
  * @ret len            Length of setting, or negative error
  */
-int fetch_ipv4_setting ( struct settings *settings, unsigned int tag,
+int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
                         struct in_addr *inp ) {
        int len;
 
-       len = fetch_setting ( settings, tag, inp, sizeof ( *inp ) );
+       len = fetch_setting ( settings, setting, inp, sizeof ( *inp ) );
        if ( len < 0 )
                return len;
        if ( len < ( int ) sizeof ( *inp ) )
@@ -418,11 +403,11 @@ int fetch_ipv4_setting ( struct settings *settings, unsigned int tag,
  * Fetch value of signed integer setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v value            Integer value to fill in
  * @ret len            Length of setting, or negative error
  */
-int fetch_int_setting ( struct settings *settings, unsigned int tag,
+int fetch_int_setting ( struct settings *settings, struct setting *setting,
                        long *value ) {
        union {
                long value;
@@ -433,7 +418,7 @@ int fetch_int_setting ( struct settings *settings, unsigned int tag,
        int i;
 
        buf.value = 0;
-       len = fetch_setting ( settings, tag, &buf, sizeof ( buf ) );
+       len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) );
        if ( len < 0 )
                return len;
        if ( len > ( int ) sizeof ( buf ) )
@@ -451,16 +436,16 @@ int fetch_int_setting ( struct settings *settings, unsigned int tag,
  * Fetch value of unsigned integer setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v value            Integer value to fill in
  * @ret len            Length of setting, or negative error
  */
-int fetch_uint_setting ( struct settings *settings, unsigned int tag,
+int fetch_uint_setting ( struct settings *settings, struct setting *setting,
                         unsigned long *value ) {
        long svalue;
        int len;
 
-       len = fetch_int_setting ( settings, tag, &svalue );
+       len = fetch_int_setting ( settings, setting, &svalue );
        if ( len < 0 )
                return len;
 
@@ -473,13 +458,13 @@ int fetch_uint_setting ( struct settings *settings, unsigned int tag,
  * Fetch value of signed integer setting, or zero
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @ret value          Setting value, or zero
  */
-long fetch_intz_setting ( struct settings *settings, unsigned int tag ) {
+long fetch_intz_setting ( struct settings *settings, struct setting *setting ){
        long value = 0;
 
-       fetch_int_setting ( settings, tag, &value );
+       fetch_int_setting ( settings, setting, &value );
        return value;
 }
 
@@ -487,80 +472,38 @@ long fetch_intz_setting ( struct settings *settings, unsigned int tag ) {
  * Fetch value of unsigned integer setting, or zero
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @ret value          Setting value, or zero
  */
 unsigned long fetch_uintz_setting ( struct settings *settings,
-                                   unsigned int tag ) {
+                                   struct setting *setting ) {
        unsigned long value = 0;
 
-       fetch_uint_setting ( settings, tag, &value );
+       fetch_uint_setting ( settings, setting, &value );
        return value;
 }
 
 /**
- * Copy settings
+ * Compare two settings
  *
- * @v dest             Destination settings block
- * @v source           Source settings block
- * @v encapsulator     Encapsulating setting tag number, or zero
- * @ret rc             Return status code
+ * @v a                        Setting to compare
+ * @v b                        Setting to compare
+ * @ret 0              Settings are the same
+ * @ret non-zero       Settings are not the same
  */
-static int copy_encap_settings ( struct settings *dest,
-                                struct settings *source,
-                                unsigned int encapsulator ) {
-       unsigned int subtag;
-       unsigned int tag;
-       int len;
-       int check_len;
-       int rc;
+int setting_cmp ( struct setting *a, struct setting *b ) {
 
-       for ( subtag = DHCP_MIN_OPTION; subtag <= DHCP_MAX_OPTION; subtag++ ) {
-               tag = DHCP_ENCAP_OPT ( encapsulator, subtag );
-               switch ( tag ) {
-               case DHCP_EB_ENCAP:
-               case DHCP_VENDOR_ENCAP:
-                       /* Process encapsulated settings */
-                       if ( ( rc = copy_encap_settings ( dest, source,
-                                                         tag ) ) != 0 )
-                               return rc;
-                       break;
-               default:
-                       /* Copy setting, if present */
-                       len = fetch_setting_len ( source, tag );
-                       if ( len < 0 )
-                               break;
-                       {
-                               char buf[len];
-
-                               check_len = fetch_setting ( source, tag, buf,
-                                                           sizeof ( buf ) );
-                               assert ( check_len == len );
-                               if ( ( rc = store_setting ( dest, tag, buf,
-                                                           sizeof(buf) )) !=0)
-                                       return rc;
-                       }
-                       break;
-               }
-       }
+       /* If the settings have tags, compare them */
+       if ( a->tag && ( a->tag == b->tag ) )
+               return 0;
 
-       return 0;
-}
-
-/**
- * Copy settings
- *
- * @v dest             Destination settings block
- * @v source           Source settings block
- * @ret rc             Return status code
- */
-int copy_settings ( struct settings *dest, struct settings *source ) {
-       return copy_encap_settings ( dest, source, 0 );
+       /* Otherwise, compare the names */
+       return strcmp ( a->name, b->name );
 }
 
 /******************************************************************************
  *
- * Named and typed setting routines
+ * Formatted setting routines
  *
  ******************************************************************************
  */
@@ -569,23 +512,22 @@ int copy_settings ( struct settings *dest, struct settings *source ) {
  * Store value of typed setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @v type             Settings type
  * @v value            Formatted setting data, or NULL
  * @ret rc             Return status code
  */
-int store_typed_setting ( struct settings *settings,
-                         unsigned int tag, struct setting_type *type,
-                         const char *value ) {
+int storef_setting ( struct settings *settings, struct setting *setting,
+                    const char *value ) {
 
        /* NULL value implies deletion.  Avoid imposing the burden of
         * checking for NULL values on each typed setting's storef()
         * method.
         */
        if ( ! value )
-               return delete_setting ( settings, tag );
+               return delete_setting ( settings, setting );
                
-       return type->storef ( settings, tag, value );
+       return setting->type->storef ( settings, setting, value );
 }
 
 /**
@@ -594,11 +536,10 @@ int store_typed_setting ( struct settings *settings,
  * @v name             Name
  * @ret setting                Named setting, or NULL
  */
-static struct named_setting * find_named_setting ( const char *name ) {
-       struct named_setting *setting;
+static struct setting * find_setting ( const char *name ) {
+       struct setting *setting;
 
-       for ( setting = named_settings ; setting < named_settings_end ;
-             setting++ ) {
+       for ( setting = settings ; setting < settings_end ; setting++ ) {
                if ( strcmp ( name, setting->name ) == 0 )
                        return setting;
        }
@@ -625,9 +566,8 @@ static struct setting_type * find_setting_type ( const char *name ) {
  * Parse setting name
  *
  * @v name             Name of setting
- * @ret settings       Settings block, or NULL
- * @ret tag            Setting tag number
- * @ret type           Setting type
+ * @v settings         Settings block to fill in
+ * @v setting          Setting to fill in
  * @ret rc             Return status code
  *
  * Interprets a name of the form
@@ -635,30 +575,29 @@ static struct setting_type * find_setting_type ( const char *name ) {
  * fields.
  */
 static int parse_setting_name ( const char *name, struct settings **settings,
-                               unsigned int *tag,
-                               struct setting_type **type ) {
+                               struct setting *setting ) {
        char tmp_name[ strlen ( name ) + 1 ];
        char *settings_name;
-       char *tag_name;
+       char *setting_name;
        char *type_name;
-       struct named_setting *named_setting;
+       struct setting *named_setting;
        char *tmp;
 
        /* Set defaults */
        *settings = &settings_root;
-       *tag = 0;
-       *type = &setting_type_hex;
+       memset ( setting, 0, sizeof ( *setting ) );
+       setting->type = &setting_type_hex;
 
-       /* Split name into "[settings_name/]tag_name[:type_name]" */
+       /* Split name into "[settings_name/]setting_name[:type_name]" */
        memcpy ( tmp_name, name, sizeof ( tmp_name ) );
-       if ( ( tag_name = strchr ( tmp_name, '/' ) ) != NULL ) {
-               *(tag_name++) = 0;
+       if ( ( setting_name = strchr ( tmp_name, '/' ) ) != NULL ) {
+               *(setting_name++) = 0;
                settings_name = tmp_name;
        } else {
-               tag_name = tmp_name;
+               setting_name = tmp_name;
                settings_name = NULL;
        }
-       if ( ( type_name = strchr ( tag_name, ':' ) ) != NULL )
+       if ( ( type_name = strchr ( setting_name, ':' ) ) != NULL )
                *(type_name++) = 0;
 
        /* Identify settings block, if specified */
@@ -672,19 +611,19 @@ static int parse_setting_name ( const char *name, struct settings **settings,
        }
 
        /* Identify tag number */
-       if ( ( named_setting = find_named_setting ( tag_name ) ) != NULL ) {
-               *tag = named_setting->tag;
-               *type = named_setting->type;
+       if ( ( named_setting = find_setting ( setting_name ) ) != NULL ) {
+               memcpy ( setting, named_setting, sizeof ( *setting ) );
        } else {
                /* Unrecognised name: try to interpret as a tag number */
-               tmp = tag_name;
+               tmp = setting_name;
                while ( 1 ) {
-                       *tag = ( ( *tag << 8 ) | strtoul ( tmp, &tmp, 0 ) );
+                       setting->tag = ( ( setting->tag << 8 ) |
+                                        strtoul ( tmp, &tmp, 0 ) );
                        if ( *tmp == 0 )
                                break;
                        if ( *tmp != '.' ) {
-                               DBG ( "Invalid tag number \"%s\" in \"%s\"\n",
-                                     tag_name, name );
+                               DBG ( "Invalid setting \"%s\" in \"%s\"\n",
+                                     setting_name, name );
                                return -ENOENT;
                        }
                        tmp++;
@@ -693,8 +632,8 @@ static int parse_setting_name ( const char *name, struct settings **settings,
 
        /* Identify setting type, if specified */
        if ( type_name ) {
-               *type = find_setting_type ( type_name );
-               if ( *type == NULL ) {
+               setting->type = find_setting_type ( type_name );
+               if ( setting->type == NULL ) {
                        DBG ( "Invalid setting type \"%s\" in \"%s\"\n",
                              type_name, name );
                        return -ENOTSUP;
@@ -711,16 +650,14 @@ static int parse_setting_name ( const char *name, struct settings **settings,
  * @v value            Formatted setting data, or NULL
  * @ret rc             Return status code
  */
-int store_named_setting ( const char *name, const char *value ) {
+int storef_named_setting ( const char *name, const char *value ) {
        struct settings *settings;
-       unsigned int tag;
-       struct setting_type *type;
+       struct setting setting;
        int rc;
 
-       if ( ( rc = parse_setting_name ( name, &settings, &tag,
-                                        &type ) ) != 0 )
+       if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 )
                return rc;
-       return store_typed_setting ( settings, tag, type, value );
+       return storef_setting ( settings, &setting, value );
 }
 
 /**
@@ -731,16 +668,14 @@ int store_named_setting ( const char *name, const char *value ) {
  * @v len              Length of buffer
  * @ret len            Length of formatted value, or negative error
  */
-int fetch_named_setting ( const char *name, char *buf, size_t len ) {
+int fetchf_named_setting ( const char *name, char *buf, size_t len ) {
        struct settings *settings;
-       unsigned int tag;
-       struct setting_type *type;
+       struct setting setting;
        int rc;
 
-       if ( ( rc = parse_setting_name ( name, &settings, &tag,
-                                        &type ) ) != 0 )
+       if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 )
                return rc;
-       return fetch_typed_setting ( settings, tag, type, buf, len );
+       return fetchf_setting ( settings, &setting, buf, len );
 }
 
 /******************************************************************************
@@ -754,27 +689,27 @@ int fetch_named_setting ( const char *name, char *buf, size_t len ) {
  * Parse and store value of string setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @v value            Formatted setting data
  * @ret rc             Return status code
  */
-static int storef_string ( struct settings *settings, unsigned int tag,
+static int storef_string ( struct settings *settings, struct setting *setting,
                           const char *value ) {
-       return store_setting ( settings, tag, value, strlen ( value ) );
+       return store_setting ( settings, setting, value, strlen ( value ) );
 }
 
 /**
  * Fetch and format value of string setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v buf              Buffer to contain formatted value
  * @v len              Length of buffer
  * @ret len            Length of formatted value, or negative error
  */
-static int fetchf_string ( struct settings *settings, unsigned int tag,
+static int fetchf_string ( struct settings *settings, struct setting *setting,
                           char *buf, size_t len ) {
-       return fetch_string_setting ( settings, tag, buf, len );
+       return fetch_string_setting ( settings, setting, buf, len );
 }
 
 /** A string setting type */
@@ -788,34 +723,34 @@ struct setting_type setting_type_string __setting_type = {
  * Parse and store value of IPv4 address setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @v value            Formatted setting data
  * @ret rc             Return status code
  */
-static int storef_ipv4 ( struct settings *settings, unsigned int tag,
+static int storef_ipv4 ( struct settings *settings, struct setting *setting,
                         const char *value ) {
        struct in_addr ipv4;
 
        if ( inet_aton ( value, &ipv4 ) == 0 )
                return -EINVAL;
-       return store_setting ( settings, tag, &ipv4, sizeof ( ipv4 ) );
+       return store_setting ( settings, setting, &ipv4, sizeof ( ipv4 ) );
 }
 
 /**
  * Fetch and format value of IPv4 address setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v buf              Buffer to contain formatted value
  * @v len              Length of buffer
  * @ret len            Length of formatted value, or negative error
  */
-static int fetchf_ipv4 ( struct settings *settings, unsigned int tag,
+static int fetchf_ipv4 ( struct settings *settings, struct setting *setting,
                         char *buf, size_t len ) {
        struct in_addr ipv4;
        int rc;
 
-       if ( ( rc = fetch_ipv4_setting ( settings, tag, &ipv4 ) ) < 0 )
+       if ( ( rc = fetch_ipv4_setting ( settings, setting, &ipv4 ) ) < 0 )
                return rc;
        return snprintf ( buf, len, inet_ntoa ( ipv4 ) );
 }
@@ -831,12 +766,12 @@ struct setting_type setting_type_ipv4 __setting_type = {
  * Parse and store value of integer setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @v value            Formatted setting data
  * @v size             Integer size, in bytes
  * @ret rc             Return status code
  */
-static int storef_int ( struct settings *settings, unsigned int tag,
+static int storef_int ( struct settings *settings, struct setting *setting,
                        const char *value, unsigned int size ) {
        union {
                uint32_t num;
@@ -847,7 +782,7 @@ static int storef_int ( struct settings *settings, unsigned int tag,
        u.num = htonl ( strtoul ( value, &endp, 0 ) );
        if ( *endp )
                return -EINVAL;
-       return store_setting ( settings, tag, 
+       return store_setting ( settings, setting, 
                               &u.bytes[ sizeof ( u ) - size ], size );
 }
 
@@ -855,59 +790,59 @@ static int storef_int ( struct settings *settings, unsigned int tag,
  * Parse and store value of 8-bit integer setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @v value            Formatted setting data
  * @v size             Integer size, in bytes
  * @ret rc             Return status code
  */
-static int storef_int8 ( struct settings *settings, unsigned int tag,
+static int storef_int8 ( struct settings *settings, struct setting *setting,
                         const char *value ) {
-       return storef_int ( settings, tag, value, 1 );
+       return storef_int ( settings, setting, value, 1 );
 }
 
 /**
  * Parse and store value of 16-bit integer setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @v value            Formatted setting data
  * @v size             Integer size, in bytes
  * @ret rc             Return status code
  */
-static int storef_int16 ( struct settings *settings, unsigned int tag,
+static int storef_int16 ( struct settings *settings, struct setting *setting,
                          const char *value ) {
-       return storef_int ( settings, tag, value, 2 );
+       return storef_int ( settings, setting, value, 2 );
 }
 
 /**
  * Parse and store value of 32-bit integer setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @v value            Formatted setting data
  * @v size             Integer size, in bytes
  * @ret rc             Return status code
  */
-static int storef_int32 ( struct settings *settings, unsigned int tag,
+static int storef_int32 ( struct settings *settings, struct setting *setting,
                          const char *value ) {
-       return storef_int ( settings, tag, value, 4 );
+       return storef_int ( settings, setting, value, 4 );
 }
 
 /**
  * Fetch and format value of signed integer setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v buf              Buffer to contain formatted value
  * @v len              Length of buffer
  * @ret len            Length of formatted value, or negative error
  */
-static int fetchf_int ( struct settings *settings, unsigned int tag,
+static int fetchf_int ( struct settings *settings, struct setting *setting,
                        char *buf, size_t len ) {
        long value;
        int rc;
 
-       if ( ( rc = fetch_int_setting ( settings, tag, &value ) ) < 0 )
+       if ( ( rc = fetch_int_setting ( settings, setting, &value ) ) < 0 )
                return rc;
        return snprintf ( buf, len, "%ld", value );
 }
@@ -916,17 +851,17 @@ static int fetchf_int ( struct settings *settings, unsigned int tag,
  * Fetch and format value of unsigned integer setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v buf              Buffer to contain formatted value
  * @v len              Length of buffer
  * @ret len            Length of formatted value, or negative error
  */
-static int fetchf_uint ( struct settings *settings, unsigned int tag,
+static int fetchf_uint ( struct settings *settings, struct setting *setting,
                         char *buf, size_t len ) {
        unsigned long value;
        int rc;
 
-       if ( ( rc = fetch_uint_setting ( settings, tag, &value ) ) < 0 )
+       if ( ( rc = fetch_uint_setting ( settings, setting, &value ) ) < 0 )
                return rc;
        return snprintf ( buf, len, "%#lx", value );
 }
@@ -977,11 +912,11 @@ struct setting_type setting_type_uint32 __setting_type = {
  * Parse and store value of hex string setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @v value            Formatted setting data
  * @ret rc             Return status code
  */
-static int storef_hex ( struct settings *settings, unsigned int tag,
+static int storef_hex ( struct settings *settings, struct setting *setting,
                        const char *value ) {
        char *ptr = ( char * ) value;
        uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
@@ -991,7 +926,7 @@ static int storef_hex ( struct settings *settings, unsigned int tag,
                bytes[len++] = strtoul ( ptr, &ptr, 16 );
                switch ( *ptr ) {
                case '\0' :
-                       return store_setting ( settings, tag, bytes, len );
+                       return store_setting ( settings, setting, bytes, len );
                case ':' :
                        ptr++;
                        break;
@@ -1005,26 +940,27 @@ static int storef_hex ( struct settings *settings, unsigned int tag,
  * Fetch and format value of hex string setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v buf              Buffer to contain formatted value
  * @v len              Length of buffer
  * @ret len            Length of formatted value, or negative error
  */
-static int fetchf_hex ( struct settings *settings, unsigned int tag,
+static int fetchf_hex ( struct settings *settings, struct setting *setting,
                        char *buf, size_t len ) {
        int raw_len;
        int check_len;
        int used = 0;
        int i;
 
-       raw_len = fetch_setting_len ( settings, tag );
+       raw_len = fetch_setting_len ( settings, setting );
        if ( raw_len < 0 )
                return raw_len;
 
        {
                uint8_t raw[raw_len];
 
-               check_len = fetch_setting ( settings, tag, raw, sizeof (raw) );
+               check_len = fetch_setting ( settings, setting, raw,
+                                           sizeof ( raw ) );
                assert ( check_len == raw_len );
                
                if ( len )
@@ -1047,83 +983,55 @@ struct setting_type setting_type_hex __setting_type = {
 
 /******************************************************************************
  *
- * Named settings
+ * Settings
  *
  ******************************************************************************
  */
 
-/** Some basic setting definitions */
-struct named_setting basic_named_settings[] __named_setting = {
-       {
-               .name = "ip",
-               .description = "IPv4 address",
-               .tag = DHCP_EB_YIADDR,
-               .type = &setting_type_ipv4,
-       },
-       {
-               .name = "netmask",
-               .description = "IPv4 subnet mask",
-               .tag = DHCP_SUBNET_MASK,
-               .type = &setting_type_ipv4,
-       },
-       {
-               .name = "gateway",
-               .description = "Default gateway",
-               .tag = DHCP_ROUTERS,
-               .type = &setting_type_ipv4,
-       },
-       {
-               .name = "dns",
-               .description = "DNS server",
-               .tag = DHCP_DNS_SERVERS,
-               .type = &setting_type_ipv4,
-       },
-       {
-               .name = "hostname",
-               .description = "Host name",
-               .tag = DHCP_HOST_NAME,
-               .type = &setting_type_string,
-       },
-       {
-               .name = "next-server",
-               .description = "TFTP server",
-               .tag = DHCP_EB_SIADDR,
-               .type = &setting_type_ipv4,
-       },
-       {
-               .name = "filename",
-               .description = "Boot filename",
-               .tag = DHCP_BOOTFILE_NAME,
-               .type = &setting_type_string,
-       },
-       {
-               .name = "root-path",
-               .description = "NFS/iSCSI root path",
-               .tag = DHCP_ROOT_PATH,
-               .type = &setting_type_string,
-       },
-       {
-               .name = "username",
-               .description = "User name",
-               .tag = DHCP_EB_USERNAME,
-               .type = &setting_type_string,
-       },
-       {
-               .name = "password",
-               .description = "Password",
-               .tag = DHCP_EB_PASSWORD,
-               .type = &setting_type_string,
-       },
-       {
-               .name = "initiator-iqn",
-               .description = "iSCSI initiator name",
-               .tag = DHCP_ISCSI_INITIATOR_IQN,
-               .type = &setting_type_string,
-       },
-       {
-               .name = "priority",
-               .description = "Priority of these settings",
-               .tag = DHCP_EB_PRIORITY,
-               .type = &setting_type_int8,
-       },
+/** Hostname setting */
+struct setting hostname_setting __setting = {
+       .name = "hostname",
+       .description = "Host name",
+       .tag = DHCP_HOST_NAME,
+       .type = &setting_type_string,
+};
+
+/** Filename setting */
+struct setting filename_setting __setting = {
+       .name = "filename",
+       .description = "Boot filename",
+       .tag = DHCP_BOOTFILE_NAME,
+       .type = &setting_type_string,
+};
+
+/** Root path setting */
+struct setting root_path_setting __setting = {
+       .name = "root-path",
+       .description = "NFS/iSCSI root path",
+       .tag = DHCP_ROOT_PATH,
+       .type = &setting_type_string,
+};
+
+/** Username setting */
+struct setting username_setting __setting = {
+       .name = "username",
+       .description = "User name",
+       .tag = DHCP_EB_USERNAME,
+       .type = &setting_type_string,
+};
+
+/** Password setting */
+struct setting password_setting __setting = {
+       .name = "password",
+       .description = "Password",
+       .tag = DHCP_EB_PASSWORD,
+       .type = &setting_type_string,
+};
+
+/** Priority setting */
+struct setting priority_setting __setting = {
+       .name = "priority",
+       .description = "Priority of these settings",
+       .tag = DHCP_EB_PRIORITY,
+       .type = &setting_type_int8,
 };
index e2fdd8f..c0c0728 100644 (file)
@@ -16,8 +16,8 @@ static int show_exec ( int argc, char **argv ) {
                return 1;
        }
 
-       if ( ( rc = fetch_named_setting ( argv[1], buf,
-                                         sizeof ( buf ) ) ) < 0 ){
+       if ( ( rc = fetchf_named_setting ( argv[1], buf,
+                                          sizeof ( buf ) ) ) < 0 ){
                printf ( "Could not find \"%s\": %s\n",
                         argv[1], strerror ( rc ) );
                return 1;
@@ -35,7 +35,7 @@ static int set_exec ( int argc, char **argv ) {
                return 1;
        }
 
-       if ( ( rc = store_named_setting ( argv[1], argv[2] ) ) != 0 ) {
+       if ( ( rc = storef_named_setting ( argv[1], argv[2] ) ) != 0 ) {
                printf ( "Could not set \"%s\"=\"%s\": %s\n",
                         argv[1], argv[2], strerror ( rc ) );
                return 1;
index 83146b5..0907bfd 100644 (file)
@@ -64,7 +64,7 @@ struct setting_widget {
        /** Settings block */
        struct settings *settings;
        /** Configuration setting */
-       struct named_setting *setting;
+       struct setting *setting;
        /** Screen row */
        unsigned int row;
        /** Screen column */
@@ -78,17 +78,17 @@ struct setting_widget {
 };
 
 /** Registered configuration settings */
-static struct named_setting named_settings[0]
-       __table_start ( struct named_setting, named_settings );
-static struct named_setting named_settings_end[0]
-       __table_end ( struct named_setting, named_settings );
-#define NUM_SETTINGS ( ( unsigned ) ( named_settings_end - named_settings ) )
+static struct setting all_settings[0]
+       __table_start ( struct setting, settings );
+static struct setting all_settings_end[0]
+       __table_end ( struct setting, settings );
+#define NUM_SETTINGS ( ( unsigned ) ( all_settings_end - all_settings ) )
 
 static void load_setting ( struct setting_widget *widget ) __nonnull;
 static int save_setting ( struct setting_widget *widget ) __nonnull;
 static void init_setting ( struct setting_widget *widget,
                            struct settings *settings,
-                           struct named_setting *setting,
+                           struct setting *setting,
                            unsigned int row, unsigned int col ) __nonnull;
 static void draw_setting ( struct setting_widget *widget ) __nonnull;
 static int edit_setting ( struct setting_widget *widget, int key ) __nonnull;
@@ -99,7 +99,7 @@ static void vmsg ( unsigned int row, const char *fmt, va_list args ) __nonnull;
 static void msg ( unsigned int row, const char *fmt, ... ) __nonnull;
 static void valert ( const char *fmt, va_list args ) __nonnull;
 static void alert ( const char *fmt, ... ) __nonnull;
-static void draw_info_row ( struct named_setting *setting ) __nonnull;
+static void draw_info_row ( struct setting *setting ) __nonnull;
 static int main_loop ( struct settings *settings ) __nonnull;
 
 /**
@@ -114,9 +114,8 @@ static void load_setting ( struct setting_widget *widget ) {
        widget->editing = 0;
 
        /* Read current setting value */
-       if ( fetch_typed_setting ( widget->settings, widget->setting->tag,
-                                  widget->setting->type, widget->value,
-                                  sizeof ( widget->value ) ) < 0 ) {
+       if ( fetchf_setting ( widget->settings, widget->setting,
+                             widget->value, sizeof ( widget->value ) ) < 0 ) {
                widget->value[0] = '\0';
        }       
 
@@ -133,8 +132,8 @@ static void load_setting ( struct setting_widget *widget ) {
  * @v widget           Setting widget
  */
 static int save_setting ( struct setting_widget *widget ) {
-       return store_typed_setting ( widget->settings, widget->setting->tag,
-                                    widget->setting->type, widget->value );
+       return storef_setting ( widget->settings, widget->setting,
+                               widget->value );
 }
 
 /**
@@ -148,7 +147,7 @@ static int save_setting ( struct setting_widget *widget ) {
  */
 static void init_setting ( struct setting_widget *widget,
                           struct settings *settings,
-                          struct named_setting *setting,
+                          struct setting *setting,
                           unsigned int row, unsigned int col ) {
 
        /* Initialise widget structure */
@@ -224,7 +223,7 @@ static int edit_setting ( struct setting_widget *widget, int key ) {
 static void init_setting_index ( struct setting_widget *widget,
                                 struct settings *settings,
                                 unsigned int index ) {
-       init_setting ( widget, settings, &named_settings[index],
+       init_setting ( widget, settings, &all_settings[index],
                       ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
 }
 
@@ -311,7 +310,7 @@ static void draw_title_row ( void ) {
  *
  * @v setting          Current configuration setting
  */
-static void draw_info_row ( struct named_setting *setting ) {
+static void draw_info_row ( struct setting *setting ) {
        clearmsg ( INFO_ROW );
        attron ( A_BOLD );
        msg ( INFO_ROW, "%s - %s", setting->name, setting->description );
index bc0e9a3..94cc201 100644 (file)
@@ -15,8 +15,8 @@
 
 struct net_device;
 struct job_interface;
+struct dhcp_options;
 struct dhcp_packet;
-struct settings;
 
 /** BOOTP/DHCP server port */
 #define BOOTPS_PORT 67
@@ -179,15 +179,6 @@ struct settings;
  */
 #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
  *
@@ -445,11 +436,19 @@ struct dhcphdr {
 /** Maximum time that we will wait for ProxyDHCP offers */
 #define PROXYDHCP_WAIT_TIME ( TICKS_PER_SEC * 1 )
 
-extern int create_dhcpdiscover ( struct net_device *netdev,
-                                void *data, size_t max_len );
-extern int create_dhcpack ( struct net_device *netdev,
-                           void *data, size_t max_len );
-extern int create_proxydhcpack ( struct net_device *netdev,
+/** Settings block name used for DHCP responses */
+#define DHCP_SETTINGS_NAME "dhcp"
+
+/** Settings block name used for ProxyDHCP responses */
+#define PROXYDHCP_SETTINGS_NAME "proxydhcp"
+
+extern int create_dhcp_packet ( struct dhcp_packet *dhcppkt,
+                               struct net_device *netdev, uint8_t msgtype,
+                               struct dhcp_options *options, 
+                               void *data, size_t max_len );
+extern int create_dhcp_request ( struct dhcp_packet *dhcppkt,
+                                struct net_device *netdev,
+                                struct dhcp_packet *dhcpoffer,
                                 void *data, size_t max_len );
 extern int start_dhcp ( struct job_interface *job, struct net_device *netdev );
 
index b16c5f2..8391a9d 100644 (file)
@@ -7,7 +7,7 @@
  *
  */
 
-#include <gpxe/dhcp.h>
+#include <stdint.h>
 
 /** A DHCP options block */
 struct dhcp_options {
index 98b8dad..179be2f 100644 (file)
@@ -9,15 +9,12 @@
 
 #include <gpxe/dhcp.h>
 #include <gpxe/dhcpopts.h>
-#include <gpxe/settings.h>
 
 /**
  * A DHCP packet
  *
  */
 struct dhcp_packet {
-       /** Settings block */
-       struct settings settings;
        /** The DHCP packet contents */
        struct dhcphdr *dhcphdr;
        /** Maximum length of the DHCP packet buffer */
@@ -28,7 +25,11 @@ struct dhcp_packet {
        struct dhcp_options options;
 };
 
-extern void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct refcnt *refcnt,
+extern int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
+                          const void *data, size_t len );
+extern int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
+                          void *data, size_t len );
+extern void dhcppkt_init ( struct dhcp_packet *dhcppkt, 
                           void *data, size_t len );
 
 #endif /* _GPXE_DHCPPKT_H */
diff --git a/src/include/gpxe/fakedhcp.h b/src/include/gpxe/fakedhcp.h
new file mode 100644 (file)
index 0000000..990b56a
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _GPXE_FAKEDHCP_H
+#define _GPXE_FAKEDHCP_H
+
+/** @file
+ *
+ * Fake DHCP packets
+ *
+ */
+
+#include <stdint.h>
+
+struct net_device;
+
+extern int create_fakedhcpdiscover ( struct net_device *netdev,
+                                    void *data, size_t max_len );
+extern int create_fakedhcpack ( struct net_device *netdev,
+                               void *data, size_t max_len );
+extern int create_fakeproxydhcpack ( struct net_device *netdev,
+                                    void *data, size_t max_len );
+
+#endif /* _GPXE_FAKEDHCP_H */
index f32d3ec..4082569 100644 (file)
 struct settings;
 struct in_addr;
 
+/** A setting */
+struct setting {
+       /** Name
+        *
+        * This is the human-readable name for the setting.
+        */
+       const char *name;
+       /** Description */
+       const char *description;
+       /** Setting type
+        *
+        * This identifies the type of setting (e.g. string, IPv4
+        * address, etc.).
+        */
+       struct setting_type *type;
+       /** DHCP option number, if applicable */
+       unsigned int tag;
+};
+
+/** Declare a configuration setting */
+#define        __setting __table ( struct setting, settings, 01 )
+
 /** Settings block operations */
 struct settings_operations {
        /** Store value of setting
         *
         * @v settings          Settings block
-        * @v tag               Setting tag number
+        * @v setting           Setting to store
         * @v data              Setting data, or NULL to clear setting
         * @v len               Length of setting data
         * @ret rc              Return status code
         */
-       int ( * store ) ( struct settings *settings, unsigned int tag,
+       int ( * store ) ( struct settings *settings, struct setting *setting,
                          const void *data, size_t len );
        /** Fetch value of setting
         *
         * @v settings          Settings block
-        * @v tag               Setting tag number
+        * @v setting           Setting to fetch
         * @v data              Buffer to fill with setting data
         * @v len               Length of buffer
         * @ret len             Length of setting data, or negative error
@@ -39,7 +61,7 @@ struct settings_operations {
         * The actual length of the setting will be returned even if
         * the buffer was too small.
         */
-       int ( * fetch ) ( struct settings *settings, unsigned int tag,
+       int ( * fetch ) ( struct settings *settings, struct setting *setting,
                          void *data, size_t len );
 };
 
@@ -74,21 +96,21 @@ struct setting_type {
        /** Parse and set value of setting
         *
         * @v settings          Settings block
-        * @v tag               Setting tag number
+        * @v setting           Setting to store
         * @v value             Formatted setting data
         * @ret rc              Return status code
         */
-       int ( * storef ) ( struct settings *settings, unsigned int tag,
+       int ( * storef ) ( struct settings *settings, struct setting *setting,
                           const char *value );
        /** Fetch and format value of setting
         *
-        * @v settings          Settings block, or NULL to search all blocks
-        * @v tag               Setting tag number
+        * @v settings          Settings block
+        * @v setting           Setting to fetch
         * @v buf               Buffer to contain formatted value
         * @v len               Length of buffer
         * @ret len             Length of formatted value, or negative error
         */
-       int ( * fetchf ) ( struct settings *settings, unsigned int tag,
+       int ( * fetchf ) ( struct settings *settings, struct setting *setting,
                           char *buf, size_t len );
 };
 
@@ -96,33 +118,6 @@ struct setting_type {
 #define        __setting_type \
        __table ( struct setting_type, setting_types, 01 )
 
-/**
- * A named setting
- *
- * This represents a single setting (e.g. "hostname"), encapsulating
- * the information about the setting's tag number and type.
- */
-struct named_setting {
-       /** Name
-        *
-        * This is the human-readable name for the setting.
-        */
-       const char *name;
-       /** Description */
-       const char *description;
-       /** Setting tag number */
-       unsigned int tag;
-       /** Setting type
-        *
-        * This identifies the type of setting (e.g. string, IPv4
-        * address, etc.).
-        */
-       struct setting_type *type;
-};
-
-/** Declare a configuration setting */
-#define        __named_setting __table ( struct named_setting, named_settings, 01 )
-
 /**
  * A settings applicator
  *
@@ -151,41 +146,49 @@ struct simple_settings {
 };
 
 extern struct settings_operations simple_settings_operations;
-
-extern int simple_settings_store ( struct settings *settings, unsigned int tag,
+extern int simple_settings_store ( struct settings *settings,
+                                  struct setting *setting,
                                   const void *data, size_t len );
-extern int simple_settings_fetch ( struct settings *settings, unsigned int tag,
+extern int simple_settings_fetch ( struct settings *settings,
+                                  struct setting *setting,
                                   void *data, size_t len );
+
 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,
+
+extern int store_setting ( struct settings *settings, struct setting *setting,
                           const void *data, size_t len );
-extern int fetch_setting ( struct settings *settings, unsigned int tag,
+extern int fetch_setting ( struct settings *settings, struct setting *setting,
                           void *data, size_t len );
-extern int copy_settings ( struct settings *dest, struct settings *source );
-extern int fetch_setting_len ( struct settings *settings, unsigned int tag );
-extern int fetch_string_setting ( struct settings *settings, unsigned int tag,
+extern int fetch_setting_len ( struct settings *settings,
+                              struct setting *setting );
+extern int fetch_string_setting ( struct settings *settings,
+                                 struct setting *setting,
                                  char *data, size_t len );
-extern int fetch_ipv4_setting ( struct settings *settings, unsigned int tag,
-                               struct in_addr *inp );
-extern int fetch_int_setting ( struct settings *settings, unsigned int tag,
-                              long *value );
-extern int fetch_uint_setting ( struct settings *settings, unsigned int tag,
+extern int fetch_ipv4_setting ( struct settings *settings,
+                               struct setting *setting, struct in_addr *inp );
+extern int fetch_int_setting ( struct settings *settings,
+                              struct setting *setting, long *value );
+extern int fetch_uint_setting ( struct settings *settings,
+                               struct setting *setting,
                                unsigned long *value );
-extern long fetch_intz_setting ( struct settings *settings, unsigned int tag );
+extern long fetch_intz_setting ( struct settings *settings,
+                                struct setting *setting );
 extern unsigned long fetch_uintz_setting ( struct settings *settings,
-                                          unsigned int tag );
+                                          struct setting *setting );
+extern int setting_cmp ( struct setting *a, struct setting *b );
+
 extern struct settings * find_child_settings ( struct settings *parent,
                                               const char *name );
 extern struct settings * find_settings ( const char *name );
-extern int store_typed_setting ( struct settings *settings,
-                                unsigned int tag, struct setting_type *type,
-                                const char *value );
-extern int store_named_setting ( const char *name, const char *value );
-extern int fetch_named_setting ( const char *name, char *buf, size_t len );
 
-extern struct setting_type setting_type_ __setting_type;
+extern int storef_setting ( struct settings *settings,
+                           struct setting *setting,
+                           const char *value );
+extern int storef_named_setting ( const char *name, const char *value );
+extern int fetchf_named_setting ( const char *name, char *buf, size_t len );
+
 extern struct setting_type setting_type_string __setting_type;
 extern struct setting_type setting_type_ipv4 __setting_type;
 extern struct setting_type setting_type_int8 __setting_type;
@@ -196,6 +199,18 @@ extern struct setting_type setting_type_uint16 __setting_type;
 extern struct setting_type setting_type_uint32 __setting_type;
 extern struct setting_type setting_type_hex __setting_type;
 
+extern struct setting ip_setting __setting;
+extern struct setting netmask_setting __setting;
+extern struct setting gateway_setting __setting;
+extern struct setting dns_setting __setting;
+extern struct setting hostname_setting __setting;
+extern struct setting filename_setting __setting;
+extern struct setting root_path_setting __setting;
+extern struct setting username_setting __setting;
+extern struct setting password_setting __setting;
+extern struct setting priority_setting __setting;
+extern struct setting bios_drive_setting __setting;
+
 /**
  * Initialise a settings block
  *
@@ -233,29 +248,28 @@ static inline void simple_settings_init ( struct simple_settings *simple,
  * Delete setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to delete
  * @ret rc             Return status code
  */
 static inline int delete_setting ( struct settings *settings,
-                                  unsigned int tag ) {
-       return store_setting ( settings, tag, NULL, 0 );
+                                  struct setting *setting ) {
+       return store_setting ( settings, setting, NULL, 0 );
 }
 
 /**
  * Fetch and format value of setting
  *
  * @v settings         Settings block, or NULL to search all blocks
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @v type             Settings type
  * @v buf              Buffer to contain formatted value
  * @v len              Length of buffer
  * @ret len            Length of formatted value, or negative error
  */
-static inline int fetch_typed_setting ( struct settings *settings,
-                                       unsigned int tag,
-                                       struct setting_type *type,
-                                       char *buf, size_t len ) {
-       return type->fetchf ( settings, tag, buf, len );
+static inline int fetchf_setting ( struct settings *settings,
+                                  struct setting *setting,
+                                  char *buf, size_t len ) {
+       return setting->type->fetchf ( settings, setting, buf, len );
 }
 
 /**
@@ -265,7 +279,7 @@ static inline int fetch_typed_setting ( struct settings *settings,
  * @ret rc             Return status code
  */
 static inline int delete_named_setting ( const char *name ) {
-       return store_named_setting ( name, NULL );
+       return storef_named_setting ( name, NULL );
 }
 
 #endif /* _GPXE_SETTINGS_H */
index 2a10b1a..302953e 100644 (file)
@@ -28,7 +28,7 @@
 #include <stdlib.h>
 #include <gpxe/uaccess.h>
 #include <gpxe/dhcp.h>
-#include <gpxe/dhcppkt.h>
+#include <gpxe/fakedhcp.h>
 #include <gpxe/device.h>
 #include <gpxe/netdevice.h>
 #include <gpxe/isapnp.h>
@@ -80,9 +80,9 @@ struct pxe_dhcp_packet_creator {
 
 /** PXE DHCP packet creators */
 static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = {
-       [CACHED_INFO_DHCPDISCOVER] = { create_dhcpdiscover },
-       [CACHED_INFO_DHCPACK] = { create_dhcpack },
-       [CACHED_INFO_BINL] = { create_proxydhcpack },
+       [CACHED_INFO_DHCPDISCOVER] = { create_fakedhcpdiscover },
+       [CACHED_INFO_DHCPACK] = { create_fakedhcpack },
+       [CACHED_INFO_BINL] = { create_fakeproxydhcpack },
 };
 
 /* The case in which the caller doesn't supply a buffer is really
index 64b310d..1898011 100644 (file)
@@ -118,6 +118,11 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options,
        ssize_t remaining = options->len;
        unsigned int option_len;
 
+       /* Sanity check */
+       if ( tag == DHCP_PAD )
+               return -ENOENT;
+
+       /* Search for option */
        while ( remaining ) {
                /* Calculate length of this option.  Abort processing
                 * if the length is malformed (i.e. takes us beyond
@@ -128,6 +133,9 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options,
                remaining -= option_len;
                if ( remaining < 0 )
                        break;
+               /* Check for explicit end marker */
+               if ( option->tag == DHCP_END )
+                       break;
                /* Check for matching tag */
                if ( option->tag == tag ) {
                        DBGC ( options, "DHCPOPT %p found %s (length %d)\n",
@@ -135,9 +143,6 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options,
                               option_len );
                        return offset;
                }
-               /* Check for explicit end marker */
-               if ( option->tag == DHCP_END )
-                       break;
                /* Check for start of matching encapsulation block */
                if ( DHCP_IS_ENCAP_OPT ( tag ) &&
                     ( option->tag == DHCP_ENCAPSULATOR ( tag ) ) ) {
@@ -151,6 +156,7 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options,
                }
                offset += option_len;
        }
+
        return -ENOENT;
 }
 
@@ -255,6 +261,10 @@ static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
        size_t new_len = ( len ? ( len + DHCP_OPTION_HEADER_LEN ) : 0 );
        int rc;
 
+       /* Sanity check */
+       if ( tag == DHCP_PAD )
+               return -ENOTTY;
+
        /* Find old instance of this option, if any */
        offset = find_dhcp_option_with_encap ( options, tag, &encap_offset );
        if ( offset >= 0 ) {
index 0a11520..1cf99d8 100644 (file)
@@ -92,20 +92,18 @@ find_dhcp_packet_field ( unsigned int tag ) {
        }
        return NULL;
 }
-                                   
+
 /**
  * Store value of DHCP packet setting
  *
- * @v settings         Settings block
+ * @v dhcppkt          DHCP packet
  * @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 dhcppkt_store ( struct settings *settings, unsigned int tag,
-                          const void *data, size_t len ) {
-       struct dhcp_packet *dhcppkt =
-               container_of ( settings, struct dhcp_packet, settings );
+int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
+                   const void *data, size_t len ) {
        struct dhcp_packet_field *field;
        int rc;
 
@@ -131,16 +129,14 @@ static int dhcppkt_store ( struct settings *settings, unsigned int tag,
 /**
  * Fetch value of DHCP packet setting
  *
- * @v settings         Settings block
+ * @v dhcppkt          DHCP packet
  * @v tag              Setting tag number
  * @v data             Buffer to fill with setting data
  * @v len              Length of buffer
  * @ret len            Length of setting data, or negative error
  */
-static int dhcppkt_fetch ( struct settings *settings, unsigned int tag,
-                          void *data, size_t len ) {
-       struct dhcp_packet *dhcppkt =
-               container_of ( settings, struct dhcp_packet, settings );
+int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
+                   void *data, size_t len ) {
        struct dhcp_packet_field *field;
        
        /* If this is a special field, return it */
@@ -156,31 +152,21 @@ static int dhcppkt_fetch ( struct settings *settings, unsigned int tag,
        return dhcpopt_fetch ( &dhcppkt->options, tag, data, len );
 }
 
-/** DHCP settings operations */
-static struct settings_operations dhcppkt_settings_operations = {
-       .store = dhcppkt_store,
-       .fetch = dhcppkt_fetch,
-};
-
 /**
  * Initialise prepopulated DHCP packet
  *
  * @v dhcppkt          Uninitialised DHCP packet
- * @v refcnt           Reference counter of containing object, or NULL
  * @v data             Memory for DHCP packet data
  * @v max_len          Length of memory for DHCP packet data
  *
  * The memory content must already be filled with valid DHCP options.
  * A zeroed block counts as a block of valid DHCP options.
  */
-void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct refcnt *refcnt,
-                   void *data, size_t len ) {
+void dhcppkt_init ( struct dhcp_packet *dhcppkt, void *data, size_t len ) {
        dhcppkt->dhcphdr = data;
        dhcppkt->max_len = len;
        dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options,
                       ( len - offsetof ( struct dhcphdr, options ) ) );
        dhcppkt->len = ( offsetof ( struct dhcphdr, options ) +
                         dhcppkt->options.len );
-       settings_init ( &dhcppkt->settings, &dhcppkt_settings_operations,
-                       refcnt, "dhcp" );
 }
diff --git a/src/net/fakedhcp.c b/src/net/fakedhcp.c
new file mode 100644 (file)
index 0000000..c3054db
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <gpxe/settings.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/dhcppkt.h>
+#include <gpxe/fakedhcp.h>
+
+/** @file
+ *
+ * Fake DHCP packets
+ *
+ */
+
+/**
+ * Copy settings to DHCP packet
+ *
+ * @v dest             Destination DHCP packet
+ * @v source           Source settings block
+ * @v encapsulator     Encapsulating setting tag number, or zero
+ * @ret rc             Return status code
+ */
+static int copy_encap_settings ( struct dhcp_packet *dest,
+                                struct settings *source,
+                                unsigned int encapsulator ) {
+       struct setting setting = { .name = "" };
+       unsigned int subtag;
+       unsigned int tag;
+       int len;
+       int check_len;
+       int rc;
+
+       for ( subtag = DHCP_MIN_OPTION; subtag <= DHCP_MAX_OPTION; subtag++ ) {
+               tag = DHCP_ENCAP_OPT ( encapsulator, subtag );
+               switch ( tag ) {
+               case DHCP_EB_ENCAP:
+               case DHCP_VENDOR_ENCAP:
+                       /* Process encapsulated settings */
+                       if ( ( rc = copy_encap_settings ( dest, source,
+                                                         tag ) ) != 0 )
+                               return rc;
+                       break;
+               default:
+                       /* Copy setting, if present */
+                       setting.tag = tag;
+                       len = fetch_setting_len ( source, &setting );
+                       if ( len < 0 )
+                               break;
+                       {
+                               char buf[len];
+
+                               check_len = fetch_setting ( source, &setting,
+                                                           buf, sizeof (buf));
+                               assert ( check_len == len );
+                               if ( ( rc = dhcppkt_store ( dest, tag, buf,
+                                                           sizeof(buf) )) !=0)
+                                       return rc;
+                       }
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * Copy settings to DHCP packet
+ *
+ * @v dest             Destination DHCP packet
+ * @v source           Source settings block
+ * @ret rc             Return status code
+ */
+static int copy_settings ( struct dhcp_packet *dest,
+                          struct settings *source ) {
+       return copy_encap_settings ( dest, source, 0 );
+}
+
+/**
+ * Create fake DHCPDISCOVER packet
+ *
+ * @v netdev           Network device
+ * @v data             Buffer for DHCP packet
+ * @v max_len          Size of DHCP packet buffer
+ * @ret rc             Return status code
+ *
+ * Used by external code.
+ */
+int create_fakedhcpdiscover ( struct net_device *netdev,
+                             void *data, size_t max_len ) {
+       struct dhcp_packet dhcppkt;
+       int rc;
+
+       if ( ( rc = create_dhcp_request ( &dhcppkt, netdev, NULL, data,
+                                         max_len ) ) != 0 ) {
+               DBG ( "Could not create DHCPDISCOVER: %s\n",
+                     strerror ( rc ) );
+               return rc;
+       }
+
+       return 0;
+}
+
+/**
+ * Create fake DHCPACK packet
+ *
+ * @v netdev           Network device
+ * @v data             Buffer for DHCP packet
+ * @v max_len          Size of DHCP packet buffer
+ * @ret rc             Return status code
+ *
+ * Used by external code.
+ */
+int create_fakedhcpack ( struct net_device *netdev,
+                        void *data, size_t max_len ) {
+       struct dhcp_packet dhcppkt;
+       int rc;
+
+       /* Create base DHCPACK packet */
+       if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL,
+                                        data, max_len ) ) != 0 ) {
+               DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
+               return rc;
+       }
+
+       /* Merge in globally-scoped settings, then netdev-specific
+        * settings.  Do it in this order so that netdev-specific
+        * settings take precedence regardless of stated priorities.
+        */
+       if ( ( rc = copy_settings ( &dhcppkt, NULL ) ) != 0 ) {
+               DBG ( "Could not set DHCPACK global settings: %s\n",
+                     strerror ( rc ) );
+               return rc;
+       }
+       if ( ( rc = copy_settings ( &dhcppkt,
+                                   netdev_settings ( netdev ) ) ) != 0 ) {
+               DBG ( "Could not set DHCPACK netdev settings: %s\n",
+                     strerror ( rc ) );
+               return rc;
+       }
+
+       return 0;
+}
+
+/**
+ * Create ProxyDHCPACK packet
+ *
+ * @v netdev           Network device
+ * @v data             Buffer for DHCP packet
+ * @v max_len          Size of DHCP packet buffer
+ * @ret rc             Return status code
+ *
+ * Used by external code.
+ */
+int create_fakeproxydhcpack ( struct net_device *netdev,
+                             void *data, size_t max_len ) {
+       struct dhcp_packet dhcppkt;
+       struct settings *settings;
+       int rc;
+
+       /* Identify ProxyDHCP settings */
+       settings = find_settings ( PROXYDHCP_SETTINGS_NAME );
+
+       /* No ProxyDHCP settings => return empty block */
+       if ( ! settings ) {
+               memset ( data, 0, max_len );
+               return 0;
+       }
+
+       /* Create base DHCPACK packet */
+       if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL,
+                                        data, max_len ) ) != 0 ) {
+               DBG ( "Could not create ProxyDHCPACK: %s\n",
+                     strerror ( rc ) );
+               return rc;
+       }
+
+       /* Merge in ProxyDHCP options */
+       if ( ( rc = copy_settings ( &dhcppkt, settings ) ) != 0 ) {
+               DBG ( "Could not set ProxyDHCPACK settings: %s\n",
+                     strerror ( rc ) );
+               return rc;
+       }
+
+       return 0;
+}
index 67bfc2d..591293b 100644 (file)
@@ -95,62 +95,6 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
        free ( miniroute );
 }
 
-/**
- * Create IPv4 routing table
- *
- * @ret rc             Return status code
- */
-static int ipv4_create_routes ( void ) {
-       struct ipv4_miniroute *miniroute;
-       struct ipv4_miniroute *tmp;
-       struct net_device *netdev;
-       struct settings *settings;
-       struct in_addr address = { 0 };
-       struct in_addr netmask = { 0 };
-       struct in_addr gateway = { INADDR_NONE };
-
-       /* Delete all existing routes */
-       list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
-               del_ipv4_miniroute ( miniroute );
-
-       /* Create a route for each configured network device */
-       for_each_netdev ( netdev ) {
-               settings = netdev_settings ( netdev );
-               /* Get IPv4 address */
-               address.s_addr = 0;
-               fetch_ipv4_setting ( settings, DHCP_EB_YIADDR, &address );
-               if ( ! address.s_addr )
-                       continue;
-               /* Calculate default netmask */
-               if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) {
-                       netmask.s_addr = htonl ( IN_CLASSA_NET );
-               } else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) {
-                       netmask.s_addr = htonl ( IN_CLASSB_NET );
-               } else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) {
-                       netmask.s_addr = htonl ( IN_CLASSC_NET );
-               } else {
-                       netmask.s_addr = 0;
-               }
-               /* Override with subnet mask, if present */
-               fetch_ipv4_setting ( settings, DHCP_SUBNET_MASK, &netmask );
-               /* Get default gateway, if present */
-               gateway.s_addr = INADDR_NONE;
-               fetch_ipv4_setting ( settings, DHCP_ROUTERS, &gateway );
-               /* Configure route */
-               miniroute = add_ipv4_miniroute ( netdev, address,
-                                                netmask, gateway );
-               if ( ! miniroute )
-                       return -ENOMEM;
-       }
-
-       return 0;
-}
-
-/** IPv4 settings applicator */
-struct settings_applicator ipv4_settings_applicator __settings_applicator = {
-       .apply = ipv4_create_routes,
-};
-
 /**
  * Perform IPv4 routing
  *
@@ -600,3 +544,90 @@ struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol = {
        .net_protocol = &ipv4_protocol,
        .check = ipv4_arp_check,
 };
+
+/******************************************************************************
+ *
+ * Settings
+ *
+ ******************************************************************************
+ */
+
+/** IPv4 address setting */
+struct setting ip_setting __setting = {
+       .name = "ip",
+       .description = "IPv4 address",
+       .tag = DHCP_EB_YIADDR,
+       .type = &setting_type_ipv4,
+};
+
+/** IPv4 subnet mask setting */
+struct setting netmask_setting __setting = {
+       .name = "netmask",
+       .description = "IPv4 subnet mask",
+       .tag = DHCP_SUBNET_MASK,
+       .type = &setting_type_ipv4,
+};
+
+/** Default gateway setting */
+struct setting gateway_setting __setting = {
+       .name = "gateway",
+       .description = "Default gateway",
+       .tag = DHCP_ROUTERS,
+       .type = &setting_type_ipv4,
+};
+
+/**
+ * Create IPv4 routing table based on configured settings
+ *
+ * @ret rc             Return status code
+ */
+static int ipv4_create_routes ( void ) {
+       struct ipv4_miniroute *miniroute;
+       struct ipv4_miniroute *tmp;
+       struct net_device *netdev;
+       struct settings *settings;
+       struct in_addr address = { 0 };
+       struct in_addr netmask = { 0 };
+       struct in_addr gateway = { INADDR_NONE };
+
+       /* Delete all existing routes */
+       list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
+               del_ipv4_miniroute ( miniroute );
+
+       /* Create a route for each configured network device */
+       for_each_netdev ( netdev ) {
+               settings = netdev_settings ( netdev );
+               /* Get IPv4 address */
+               address.s_addr = 0;
+               fetch_ipv4_setting ( settings, &ip_setting, &address );
+               if ( ! address.s_addr )
+                       continue;
+               /* Calculate default netmask */
+               if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) {
+                       netmask.s_addr = htonl ( IN_CLASSA_NET );
+               } else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) {
+                       netmask.s_addr = htonl ( IN_CLASSB_NET );
+               } else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) {
+                       netmask.s_addr = htonl ( IN_CLASSC_NET );
+               } else {
+                       netmask.s_addr = 0;
+               }
+               /* Override with subnet mask, if present */
+               fetch_ipv4_setting ( settings, &netmask_setting, &netmask );
+               /* Get default gateway, if present */
+               gateway.s_addr = INADDR_NONE;
+               fetch_ipv4_setting ( settings, &gateway_setting, &gateway );
+               /* Configure route */
+               miniroute = add_ipv4_miniroute ( netdev, address,
+                                                netmask, gateway );
+               if ( ! miniroute )
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/** IPv4 settings applicator */
+struct settings_applicator ipv4_settings_applicator __settings_applicator = {
+       .apply = ipv4_create_routes,
+};
index c8e630a..44aca7d 100644 (file)
  *
  */
 
+/** Network device named settings */
+struct setting mac_setting __setting = {
+       .name = "mac",
+       .description = "MAC address",
+       .type = &setting_type_hex,
+};
+
 /**
  * Store value of network device setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to store
  * @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,
+static int netdev_store ( struct settings *settings, struct setting *setting,
                          const void *data, size_t len ) {
        struct net_device *netdev = container_of ( settings, struct net_device,
                                                   settings.settings );
 
-       switch ( tag ) {
-       case DHCP_EB_MAC:
+       if ( setting_cmp ( setting, &mac_setting ) == 0 ) {
                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 );
+       } else {
+               return simple_settings_store ( settings, setting, data, len );
        }
 }
 
@@ -57,24 +63,23 @@ static int netdev_store ( struct settings *settings, unsigned int tag,
  * Fetch value of network device setting
  *
  * @v settings         Settings block
- * @v tag              Setting tag number
+ * @v setting          Setting to fetch
  * @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,
+static int netdev_fetch ( struct settings *settings, struct setting *setting,
                          void *data, size_t len ) {
        struct net_device *netdev = container_of ( settings, struct net_device,
                                                   settings.settings );
 
-       switch ( tag ) {
-       case DHCP_EB_MAC:
+       if ( setting_cmp ( setting, &mac_setting ) == 0 ) {
                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 );
+       } else {
+               return simple_settings_fetch ( settings, setting, data, len );
        }
 }
 
@@ -83,13 +88,3 @@ 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 f071b04..c01ca44 100644 (file)
@@ -1591,14 +1591,22 @@ int iscsi_attach ( struct scsi_device *scsi, const char *root_path ) {
 
 /****************************************************************************
  *
- * Settings applicators
+ * Settings
  *
  */
 
+/** iSCSI initiator IQN setting */
+struct setting initiator_iqn_setting __setting = {
+       .name = "initiator-iqn",
+       .description = "iSCSI initiator name",
+       .tag = DHCP_ISCSI_INITIATOR_IQN,
+       .type = &setting_type_string,
+};
+
 /** An iSCSI string setting */
 struct iscsi_string_setting {
-       /** Setting tag number */
-       unsigned int tag;
+       /** Setting */
+       struct setting *setting;
        /** String to update */
        char **string;
        /** String prefix */
@@ -1608,22 +1616,22 @@ struct iscsi_string_setting {
 /** iSCSI string settings */
 static struct iscsi_string_setting iscsi_string_settings[] = {
        {
-               .tag = DHCP_ISCSI_INITIATOR_IQN,
+               .setting = &initiator_iqn_setting,
                .string = &iscsi_explicit_initiator_iqn,
                .prefix = "",
        },
        {
-               .tag = DHCP_EB_USERNAME,
+               .setting = &username_setting,
                .string = &iscsi_username,
                .prefix = "",
        },
        {
-               .tag = DHCP_EB_PASSWORD,
+               .setting = &password_setting,
                .string = &iscsi_password,
                .prefix = "",
        },
        {
-               .tag = DHCP_HOST_NAME,
+               .setting = &hostname_setting,
                .string = &iscsi_default_initiator_iqn,
                .prefix = "iqn.2000-09.org.etherboot:",
        },
@@ -1648,7 +1656,7 @@ static int apply_iscsi_string_setting ( struct iscsi_string_setting *setting ){
 
        /* Allocate new string */
        prefix_len = strlen ( setting->prefix );
-       setting_len = fetch_setting_len ( NULL, setting->tag );
+       setting_len = fetch_setting_len ( NULL, setting->setting );
        if ( setting_len < 0 ) {
                /* Missing settings are not errors; leave strings as NULL */
                return 0;
@@ -1660,7 +1668,7 @@ static int apply_iscsi_string_setting ( struct iscsi_string_setting *setting ){
 
        /* Fill new string */
        strcpy ( p, setting->prefix );
-       check_len = fetch_string_setting ( NULL, setting->tag,
+       check_len = fetch_string_setting ( NULL, setting->setting,
                                           ( p + prefix_len ),
                                           ( len - prefix_len ) );
        assert ( check_len == setting_len );
@@ -1682,8 +1690,8 @@ static int apply_iscsi_settings ( void ) {
                            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 );
+                       DBG ( "iSCSI could not apply setting %s\n",
+                             setting->setting->name );
                        return rc;
                }
        }
index 8789f92..98b8af0 100644 (file)
@@ -130,9 +130,6 @@ static uint32_t dhcp_xid ( struct net_device *netdev ) {
        return xid;
 }
 
-/** Settings block name used for ProxyDHCP responses */
-#define PROXYDHCP_SETTINGS_NAME "proxydhcp"
-
 /**
  * Create a DHCP packet
  *
@@ -180,12 +177,12 @@ int create_dhcp_packet ( struct dhcp_packet *dhcppkt,
        memcpy ( dhcphdr->chaddr, netdev->ll_addr, hlen );
        memcpy ( dhcphdr->options, options->data, options_len );
 
-       /* Initialise DHCP packet structure and settings interface */
+       /* Initialise DHCP packet structure */
        memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
-       dhcppkt_init ( dhcppkt, NULL, data, max_len );
+       dhcppkt_init ( dhcppkt, data, max_len );
        
        /* Set DHCP_MESSAGE_TYPE option */
-       if ( ( rc = store_setting ( &dhcppkt->settings, DHCP_MESSAGE_TYPE,
+       if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_MESSAGE_TYPE,
                                    &msgtype, sizeof ( msgtype ) ) ) != 0 )
                return rc;
 
@@ -230,10 +227,10 @@ struct dhcp_client_uuid {
  * @v max_len          Size of DHCP packet buffer
  * @ret rc             Return status code
  */
-static int create_dhcp_request ( struct dhcp_packet *dhcppkt,
-                                struct net_device *netdev,
-                                struct dhcp_packet *dhcpoffer,
-                                void *data, size_t max_len ) {
+int create_dhcp_request ( struct dhcp_packet *dhcppkt,
+                         struct net_device *netdev,
+                         struct dhcp_packet *dhcpoffer,
+                         void *data, size_t max_len ) {
        struct device_description *desc = &netdev->dev->desc;
        struct dhcp_netdev_desc dhcp_desc;
        struct dhcp_client_id client_id;
@@ -258,27 +255,26 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt,
                struct in_addr server_id;
                struct in_addr requested_ip;
 
-               if ( ( rc = fetch_ipv4_setting ( &dhcpoffer->settings,
-                                                DHCP_SERVER_IDENTIFIER,
-                                                &server_id ) ) < 0 ) {
+               if ( dhcppkt_fetch ( dhcpoffer, DHCP_SERVER_IDENTIFIER,
+                                    &server_id, sizeof ( server_id ) )
+                    != sizeof ( server_id ) ) {
                        DBG ( "DHCP offer missing server identifier\n" );
                        return -EINVAL;
                }
-               if ( ( rc = fetch_ipv4_setting ( &dhcpoffer->settings,
-                                                DHCP_EB_YIADDR,
-                                                &requested_ip ) ) < 0 ) {
+               if ( dhcppkt_fetch ( dhcpoffer, DHCP_EB_YIADDR,
+                                    &requested_ip, sizeof ( requested_ip ) )
+                    != sizeof ( requested_ip ) ) {
                        DBG ( "DHCP offer missing IP address\n" );
                        return -EINVAL;
                }
-               if ( ( rc = store_setting ( &dhcppkt->settings,
-                                           DHCP_SERVER_IDENTIFIER, &server_id,
+               if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
+                                           &server_id,
                                            sizeof ( server_id ) ) ) != 0 ) {
                        DBG ( "DHCP could not set server identifier: %s\n ",
                              strerror ( rc ) );
                        return rc;
                }
-               if ( ( rc = store_setting ( &dhcppkt->settings,
-                                           DHCP_REQUESTED_ADDRESS,
+               if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS,
                                            &requested_ip,
                                            sizeof ( requested_ip ) ) ) != 0 ){
                        DBG ( "DHCP could not set requested address: %s\n",
@@ -289,8 +285,8 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt,
 
        /* Add options to identify the feature list */
        dhcp_features_len = ( dhcp_features_end - dhcp_features );
-       if ( ( rc = store_setting ( &dhcppkt->settings, DHCP_EB_ENCAP,
-                                   dhcp_features, dhcp_features_len ) ) !=0 ){
+       if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_ENCAP, dhcp_features,
+                                   dhcp_features_len ) ) != 0 ) {
                DBG ( "DHCP could not set features list option: %s\n",
                      strerror ( rc ) );
                return rc;
@@ -300,8 +296,8 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt,
        dhcp_desc.type = desc->bus_type;
        dhcp_desc.vendor = htons ( desc->vendor );
        dhcp_desc.device = htons ( desc->device );
-       if ( ( rc = store_setting ( &dhcppkt->settings, DHCP_EB_BUS_ID,
-                                   &dhcp_desc, sizeof ( dhcp_desc ) ) ) !=0 ){
+       if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_BUS_ID, &dhcp_desc,
+                                   sizeof ( dhcp_desc ) ) ) != 0 ) {
                DBG ( "DHCP could not set bus ID option: %s\n",
                      strerror ( rc ) );
                return rc;
@@ -314,8 +310,8 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt,
        ll_addr_len = netdev->ll_protocol->ll_addr_len;
        assert ( ll_addr_len <= sizeof ( client_id.ll_addr ) );
        memcpy ( client_id.ll_addr, netdev->ll_addr, ll_addr_len );
-       if ( ( rc = store_setting ( &dhcppkt->settings, DHCP_CLIENT_ID,
-                                   &client_id, ( ll_addr_len + 1 ) ) ) != 0 ){
+       if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_ID, &client_id,
+                                   ( ll_addr_len + 1 ) ) ) != 0 ) {
                DBG ( "DHCP could not set client ID: %s\n",
                      strerror ( rc ) );
                return rc;
@@ -324,8 +320,8 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt,
        /* Add client UUID, if we have one.  Required for PXE. */
        client_uuid.type = DHCP_CLIENT_UUID_TYPE;
        if ( ( rc = get_uuid ( &client_uuid.uuid ) ) == 0 ) {
-               if ( ( rc = store_setting ( &dhcppkt->settings,
-                                           DHCP_CLIENT_UUID, &client_uuid,
+               if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_UUID,
+                                           &client_uuid,
                                            sizeof ( client_uuid ) ) ) != 0 ) {
                        DBG ( "DHCP could not set client UUID: %s\n",
                              strerror ( rc ) );
@@ -336,169 +332,109 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt,
        return 0;
 }
 
-/**
- * Create DHCPDISCOVER packet
+/****************************************************************************
  *
- * @v netdev           Network device
- * @v data             Buffer for DHCP packet
- * @v max_len          Size of DHCP packet buffer
- * @ret rc             Return status code
+ * DHCP settings
  *
- * Used by external code.
  */
-int create_dhcpdiscover ( struct net_device *netdev,
-                         void *data, size_t max_len ) {
-       struct dhcp_packet dhcppkt;
-       int rc;
 
-       if ( ( rc = create_dhcp_request ( &dhcppkt, netdev, NULL, data,
-                                         max_len ) ) != 0 ) {
-               DBG ( "Could not create DHCPDISCOVER: %s\n",
-                     strerror ( rc ) );
-               return rc;
-       }
-
-       return 0;
-}
+/** A DHCP settings block */
+struct dhcp_settings {
+       /** Reference counter */
+       struct refcnt refcnt;
+       /** Containing I/O buffer */
+       struct io_buffer *iobuf;
+       /** DHCP packet */
+       struct dhcp_packet dhcppkt;
+       /** Setting interface */
+       struct settings settings;
+};
 
 /**
- * Create DHCPACK packet
+ * Free DHCP settings block
  *
- * @v netdev           Network device
- * @v data             Buffer for DHCP packet
- * @v max_len          Size of DHCP packet buffer
- * @ret rc             Return status code
- *
- * Used by external code.
+ * @v refcnt           Reference counter
  */
-int create_dhcpack ( struct net_device *netdev,
-                    void *data, size_t max_len ) {
-       struct dhcp_packet dhcppkt;
-       int rc;
-
-       /* Create base DHCPACK packet */
-       if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL,
-                                        data, max_len ) ) != 0 ) {
-               DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
-               return rc;
-       }
-
-       /* Merge in globally-scoped settings, then netdev-specific
-        * settings.  Do it in this order so that netdev-specific
-        * settings take precedence regardless of stated priorities.
-        */
-       if ( ( rc = copy_settings ( &dhcppkt.settings, NULL ) ) != 0 ) {
-               DBG ( "Could not set DHCPACK global settings: %s\n",
-                     strerror ( rc ) );
-               return rc;
-       }
-       if ( ( rc = copy_settings ( &dhcppkt.settings,
-                                   netdev_settings ( netdev ) ) ) != 0 ) {
-               DBG ( "Could not set DHCPACK netdev settings: %s\n",
-                     strerror ( rc ) );
-               return rc;
-       }
+static void dhcpset_free ( struct refcnt *refcnt ) {
+       struct dhcp_settings *dhcpset =
+               container_of ( refcnt, struct dhcp_settings, refcnt );
 
-       return 0;
+       free_iob ( dhcpset->iobuf );
+       free ( dhcpset );
 }
 
 /**
- * Create ProxyDHCPACK packet
- *
- * @v netdev           Network device
- * @v data             Buffer for DHCP packet
- * @v max_len          Size of DHCP packet buffer
- * @ret rc             Return status code
+ * Decrement reference count on DHCP settings block
  *
- * Used by external code.
+ * @v dhcpset          DHCP settings block
  */
-int create_proxydhcpack ( struct net_device *netdev,
-                         void *data, size_t max_len ) {
-       struct dhcp_packet dhcppkt;
-       struct settings *settings;
-       int rc;
-
-       /* Identify ProxyDHCP settings */
-       settings = find_settings ( PROXYDHCP_SETTINGS_NAME );
-
-       /* No ProxyDHCP settings => return empty block */
-       if ( ! settings ) {
-               memset ( data, 0, max_len );
-               return 0;
-       }
-
-       /* Create base DHCPACK packet */
-       if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL,
-                                        data, max_len ) ) != 0 ) {
-               DBG ( "Could not create ProxyDHCPACK: %s\n",
-                     strerror ( rc ) );
-               return rc;
-       }
-
-       /* Merge in ProxyDHCP options */
-       if ( ( rc = copy_settings ( &dhcppkt.settings, settings ) ) != 0 ) {
-               DBG ( "Could not set ProxyDHCPACK settings: %s\n",
-                     strerror ( rc ) );
-               return rc;
-       }
-
-       return 0;
+static inline void dhcpset_put ( struct dhcp_settings *dhcpset ) {
+       ref_put ( &dhcpset->refcnt );
 }
 
-/****************************************************************************
- *
- * DHCP packets contained in I/O buffers
+/**
+ * Store value of DHCP setting
  *
+ * @v settings         Settings block
+ * @v setting          Setting to store
+ * @v data             Setting data, or NULL to clear setting
+ * @v len              Length of setting data
+ * @ret rc             Return status code
  */
+static int dhcpset_store ( struct settings *settings, struct setting *setting,
+                          const void *data, size_t len ) {
+       struct dhcp_settings *dhcpset =
+               container_of ( settings, struct dhcp_settings, settings );
 
-/** A DHCP packet contained in an I/O buffer */
-struct dhcp_iobuf_packet {
-       /** DHCP packet */
-       struct dhcp_packet dhcppkt;
-       /** Reference counter */
-       struct refcnt refcnt;
-       /** Containing I/O buffer */
-       struct io_buffer *iobuf;
-};
+       return dhcppkt_store ( &dhcpset->dhcppkt, setting->tag, data, len );
+}
 
 /**
- * Free DHCP packet contained in an I/O buffer
+ * Fetch value of setting
  *
- * @v refcnt           Reference counter
+ * @v settings         Settings block, or NULL to search all blocks
+ * @v setting          Setting to fetch
+ * @v data             Buffer to fill with setting data
+ * @v len              Length of buffer
+ * @ret len            Length of setting data, or negative error
  */
-static void dhcpiob_free ( struct refcnt *refcnt ) {
-       struct dhcp_iobuf_packet *dhcpiob =
-               container_of ( refcnt, struct dhcp_iobuf_packet, refcnt );
+static int dhcpset_fetch ( struct settings *settings, struct setting *setting,
+                          void *data, size_t len ) {
+       struct dhcp_settings *dhcpset =
+               container_of ( settings, struct dhcp_settings, settings );
 
-       free_iob ( dhcpiob->iobuf );
-       free ( dhcpiob );
+       return dhcppkt_fetch ( &dhcpset->dhcppkt, setting->tag, data, len );
 }
 
+/** DHCP settings operations */
+static struct settings_operations dhcpset_settings_operations = {
+       .store = dhcpset_store,
+       .fetch = dhcpset_fetch,
+};
+
 /**
- * Create DHCP packet from I/O buffer
+ * Create DHCP setting block from I/O buffer
  *
  * @v iobuf            I/O buffer
- * @ret dhcpiob                DHCP packet contained in I/O buffer
+ * @ret dhcpset                DHCP settings block
  *
  * This function takes ownership of the I/O buffer.  Future accesses
- * must be via the @c dhcpiob data structure.
+ * must be via the @c dhcpset data structure.
  */
-static struct dhcp_iobuf_packet * dhcpiob_create ( struct io_buffer *iobuf ) {
-       struct dhcp_iobuf_packet *dhcpiob;
-
-       dhcpiob = zalloc ( sizeof ( *dhcpiob ) );
-       if ( dhcpiob ) {
-               dhcpiob->refcnt.free = dhcpiob_free;
-               dhcpiob->iobuf = iobuf;
-               dhcppkt_init ( &dhcpiob->dhcppkt, &dhcpiob->refcnt,
+static struct dhcp_settings * dhcpset_create_iob ( struct io_buffer *iobuf ) {
+       struct dhcp_settings *dhcpset;
+
+       dhcpset = zalloc ( sizeof ( *dhcpset ) );
+       if ( dhcpset ) {
+               dhcpset->refcnt.free = dhcpset_free;
+               dhcpset->iobuf = iobuf;
+               dhcppkt_init ( &dhcpset->dhcppkt,
                               iobuf->data, iob_len ( iobuf ) );
+               settings_init ( &dhcpset->settings,
+                               &dhcpset_settings_operations, &dhcpset->refcnt,
+                               DHCP_SETTINGS_NAME );
        }
-       return dhcpiob;
-}
-
-static void dhcpiob_put ( struct dhcp_iobuf_packet *dhcpiob ) {
-       if ( dhcpiob )
-               ref_put ( &dhcpiob->refcnt );
+       return dhcpset;
 }
 
 /****************************************************************************
@@ -526,9 +462,9 @@ struct dhcp_session {
         */
        int state;
        /** Response obtained from DHCP server */
-       struct dhcp_iobuf_packet *response;
+       struct dhcp_settings *response;
        /** Response obtained from ProxyDHCP server */
-       struct dhcp_iobuf_packet *proxy_response;
+       struct dhcp_settings *proxy_response;
        /** Retransmission timer */
        struct retry_timer timer;
        /** Session start time (in ticks) */
@@ -545,8 +481,8 @@ static void dhcp_free ( struct refcnt *refcnt ) {
                container_of ( refcnt, struct dhcp_session, refcnt );
 
        netdev_put ( dhcp->netdev );
-       dhcpiob_put ( dhcp->response );
-       dhcpiob_put ( dhcp->proxy_response );
+       dhcpset_put ( dhcp->response );
+       dhcpset_put ( dhcp->proxy_response );
        free ( dhcp );
 }
 
@@ -584,7 +520,7 @@ static int dhcp_register_settings ( struct dhcp_session *dhcp ) {
 
        /* Register ProxyDHCP settings, if present */
        if ( dhcp->proxy_response ) {
-               settings = &dhcp->proxy_response->dhcppkt.settings;
+               settings = &dhcp->proxy_response->settings;
                settings->name = PROXYDHCP_SETTINGS_NAME;
                old_settings = find_settings ( settings->name );
                if ( old_settings )
@@ -595,7 +531,7 @@ static int dhcp_register_settings ( struct dhcp_session *dhcp ) {
 
        /* Register DHCP settings */
        parent = netdev_settings ( dhcp->netdev );
-       settings = &dhcp->response->dhcppkt.settings;
+       settings = &dhcp->response->settings;
        old_settings = find_child_settings ( parent, settings->name );
        if ( old_settings )
                unregister_settings ( old_settings );
@@ -701,24 +637,24 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
                              struct xfer_metadata *meta __unused ) {
        struct dhcp_session *dhcp =
                container_of ( xfer, struct dhcp_session, xfer );
-       struct dhcp_iobuf_packet *response;
-       struct dhcp_iobuf_packet **store_response;
+       struct dhcp_settings *response;
+       struct dhcp_settings **store_response;
        struct dhcphdr *dhcphdr;
-       struct settings *settings;
-       unsigned int msgtype;
+       uint8_t msgtype = 0;
+       uint8_t priority = 0;
+       uint8_t existing_priority = 0;
        unsigned long elapsed;
        int is_proxy;
-       int ignore_proxy;
+       uint8_t ignore_proxy = 0;
        int rc;
 
        /* Convert packet into a DHCP-packet-in-iobuf */
-       response = dhcpiob_create ( iobuf );
+       response = dhcpset_create_iob ( iobuf );
        if ( ! response ) {
                DBGC ( dhcp, "DHCP %p could not store DHCP packet\n", dhcp );
                return -ENOMEM;
        }
        dhcphdr = response->dhcppkt.dhcphdr;
-       settings = &response->dhcppkt.settings;
 
        /* Check for matching transaction ID */
        if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
@@ -730,7 +666,8 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
 
        /* Determine and verify message type */
        is_proxy = ( dhcphdr->yiaddr.s_addr == 0 );
-       msgtype = fetch_uintz_setting ( settings, DHCP_MESSAGE_TYPE );
+       dhcppkt_fetch ( &response->dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
+                       sizeof ( msgtype ) );
        DBGC ( dhcp, "DHCP %p received %s%s\n", dhcp,
               ( is_proxy ? "Proxy" : "" ), dhcp_msgtype_name ( msgtype ) );
        if ( ( ( dhcp->state != DHCPDISCOVER ) || ( msgtype != DHCPOFFER ) ) &&
@@ -746,14 +683,18 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
         * currently-stored options.
         */
        store_response = ( is_proxy ? &dhcp->proxy_response : &dhcp->response);
-       if ( ( ! *store_response ) || 
-            ( fetch_uintz_setting ( settings, DHCP_EB_PRIORITY ) >=
-              fetch_uintz_setting ( &(*store_response)->dhcppkt.settings,
-                                    DHCP_EB_PRIORITY ) ) ) {
-               dhcpiob_put ( *store_response );
+       if ( *store_response ) {
+               dhcppkt_fetch ( &(*store_response)->dhcppkt, DHCP_EB_PRIORITY,
+                               &existing_priority,
+                               sizeof ( existing_priority ) );
+       }
+       dhcppkt_fetch ( &response->dhcppkt, DHCP_EB_PRIORITY, &priority,
+                       sizeof ( priority ) );
+       if ( priority >= existing_priority ) {
+               dhcpset_put ( *store_response );
                *store_response = response;
        } else {
-               dhcpiob_put ( response );
+               dhcpset_put ( response );
        }
 
        /* If we don't yet have a standard DHCP response (i.e. one
@@ -763,8 +704,8 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
                goto out;
 
        /* Handle DHCP response */
-       ignore_proxy = fetch_uintz_setting ( &dhcp->response->dhcppkt.settings,
-                                            DHCP_EB_NO_PROXYDHCP );
+       dhcppkt_fetch ( &dhcp->response->dhcppkt, DHCP_EB_NO_PROXYDHCP,
+                       &ignore_proxy, sizeof ( ignore_proxy ) );
        switch ( dhcp->state ) {
        case DHCPDISCOVER:
                /* If we have allowed sufficient time for ProxyDHCP
@@ -780,7 +721,7 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
        case DHCPREQUEST:
                /* DHCP finished; register options and exit */
                if ( ignore_proxy && dhcp->proxy_response ) {
-                       dhcpiob_put ( dhcp->proxy_response );
+                       dhcpset_put ( dhcp->proxy_response );
                        dhcp->proxy_response = NULL;
                }
                if ( ( rc = dhcp_register_settings ( dhcp ) ) != 0 ) {
@@ -797,7 +738,7 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
        return 0;
 
  out_discard:
-       dhcpiob_put ( response );
+       dhcpset_put ( response );
        return 0;
 }
 
index 5e632d1..1bcdbc7 100644 (file)
@@ -506,6 +506,21 @@ struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = {
        .resolv = dns_resolv,
 };
 
+/******************************************************************************
+ *
+ * Settings
+ *
+ ******************************************************************************
+ */
+
+/** DNS server setting */
+struct setting dns_setting __setting = {
+       .name = "dns",
+       .description = "DNS server",
+       .tag = DHCP_DNS_SERVERS,
+       .type = &setting_type_ipv4,
+};
+
 /**
  * Apply nameserver setting
  *
@@ -516,7 +531,7 @@ static int apply_nameserver_setting ( void ) {
                ( struct sockaddr_in * ) &nameserver;
        int len;
 
-       if ( ( len = fetch_ipv4_setting ( NULL, DHCP_DNS_SERVERS,
+       if ( ( len = fetch_ipv4_setting ( NULL, &dns_setting,
                                          &sin_nameserver->sin_addr ) ) >= 0 ){
                sin_nameserver->sin_family = AF_INET;
                DBG ( "DNS using nameserver %s\n",
index 8bd2b80..e49bcf9 100644 (file)
@@ -1093,6 +1093,21 @@ struct uri_opener mtftp_uri_opener __uri_opener = {
        .open   = mtftp_open,
 };
 
+/******************************************************************************
+ *
+ * Settings
+ *
+ ******************************************************************************
+ */
+
+/** TFTP server setting */
+struct setting next_server_setting __setting = {
+       .name = "next-server",
+       .description = "TFTP server",
+       .tag = DHCP_EB_SIADDR,
+       .type = &setting_type_ipv4,
+};
+
 /**
  * Apply TFTP configuration settings
  *
@@ -1106,7 +1121,7 @@ static int tftp_apply_settings ( void ) {
 
        /* Retrieve TFTP server setting */
        last_tftp_server = tftp_server;
-       fetch_ipv4_setting ( NULL, DHCP_EB_SIADDR, &tftp_server );
+       fetch_ipv4_setting ( NULL, &next_server_setting, &tftp_server );
 
        /* If TFTP server setting has changed, set the current working
         * URI to match.  Do it only when the TFTP server has changed
index 6bf56a8..f0e481b 100644 (file)
@@ -5,7 +5,6 @@
 #include <gpxe/aoe.h>
 #include <gpxe/ata.h>
 #include <gpxe/netdevice.h>
-#include <gpxe/dhcp.h>
 #include <gpxe/settings.h>
 #include <gpxe/abft.h>
 #include <int13.h>
@@ -56,7 +55,6 @@ int aoeboot ( const char *root_path ) {
                container_of ( ata.backend, struct aoe_session, refcnt );
        abft_fill_data ( aoe );
 
-       drive.drive = fetch_uintz_setting ( NULL, DHCP_EB_BIOS_DRIVE );
        drive.blockdev = &ata.blockdev;
 
        register_int13_drive ( &drive );
index bc86d05..c1a61ec 100644 (file)
@@ -147,14 +147,14 @@ static int netboot ( struct net_device *netdev ) {
                return rc;
 
        /* Try to download and boot whatever we are given as a filename */
-       fetch_string_setting ( NULL, DHCP_BOOTFILE_NAME, buf, sizeof ( buf ) );
+       fetch_string_setting ( NULL, &filename_setting, buf, sizeof ( buf ) );
        if ( buf[0] ) {
                printf ( "Booting from filename \"%s\"\n", buf );
                return boot_filename ( buf );
        }
        
        /* No filename; try the root path */
-       fetch_string_setting ( NULL, DHCP_ROOT_PATH, buf, sizeof ( buf ) );
+       fetch_string_setting ( NULL, &root_path_setting, buf, sizeof ( buf ) );
        if ( buf[0] ) {
                printf ( "Booting from root path \"%s\"\n", buf );
                return boot_root_path ( buf );
index c3a477c..99edc87 100644 (file)
@@ -2,7 +2,6 @@
 #include <string.h>
 #include <stdio.h>
 #include <gpxe/iscsi.h>
-#include <gpxe/dhcp.h>
 #include <gpxe/settings.h>
 #include <gpxe/netdevice.h>
 #include <gpxe/ibft.h>
@@ -46,7 +45,6 @@ int iscsiboot ( const char *root_path ) {
                goto error_init;
        }
 
-       drive.drive = fetch_uintz_setting ( NULL, DHCP_EB_BIOS_DRIVE );
        drive.blockdev = &scsi.blockdev;
 
        /* FIXME: ugly, ugly hack */