david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[Settings] Remove assumption that all settings have DHCP tag values

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.
This commit is contained in:
Michael Brown 2008-03-25 20:46:16 +00:00
parent ee5bdb0d75
commit 92d15eff30
24 changed files with 865 additions and 720 deletions

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

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

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

View File

@ -35,43 +35,24 @@
*
*/
/** 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];
/* If the settings have tags, compare them */
if ( a->tag && ( a->tag == b->tag ) )
return 0;
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;
}
}
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,
};

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

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

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

View File

@ -7,7 +7,7 @@
*
*/
#include <gpxe/dhcp.h>
#include <stdint.h>
/** A DHCP options block */
struct dhcp_options {

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

View File

@ -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 */

View File

@ -16,22 +16,44 @@
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 */

View 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

View 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 ) {

View 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" );
}

205
src/net/fakedhcp.c Normal file
View File

@ -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;
}

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

View File

@ -28,28 +28,34 @@
*
*/
/** 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,
},
};

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

View 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
*
* 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;
}
/**
* Create 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_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;
}
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_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;
}
/****************************************************************************
*
* DHCP packets contained in I/O buffers
* DHCP settings
*
*/
/** A DHCP packet contained in an I/O buffer */
struct dhcp_iobuf_packet {
/** DHCP packet */
struct dhcp_packet dhcppkt;
/** 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;
};
/**
* Free DHCP packet contained in an I/O buffer
* Free DHCP settings block
*
* @v refcnt Reference counter
*/
static void dhcpiob_free ( struct refcnt *refcnt ) {
struct dhcp_iobuf_packet *dhcpiob =
container_of ( refcnt, struct dhcp_iobuf_packet, refcnt );
static void dhcpset_free ( struct refcnt *refcnt ) {
struct dhcp_settings *dhcpset =
container_of ( refcnt, struct dhcp_settings, refcnt );
free_iob ( dhcpiob->iobuf );
free ( dhcpiob );
free_iob ( dhcpset->iobuf );
free ( dhcpset );
}
/**
* Create DHCP packet from I/O buffer
* Decrement reference count on DHCP settings block
*
* @v iobuf I/O buffer
* @ret dhcpiob DHCP packet contained in I/O buffer
*
* This function takes ownership of the I/O buffer. Future accesses
* must be via the @c dhcpiob data structure.
* @v dhcpset DHCP settings block
*/
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,
iobuf->data, iob_len ( iobuf ) );
}
return dhcpiob;
static inline void dhcpset_put ( struct dhcp_settings *dhcpset ) {
ref_put ( &dhcpset->refcnt );
}
static void dhcpiob_put ( struct dhcp_iobuf_packet *dhcpiob ) {
if ( dhcpiob )
ref_put ( &dhcpiob->refcnt );
/**
* 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 );
return dhcppkt_store ( &dhcpset->dhcppkt, setting->tag, data, len );
}
/**
* Fetch value of setting
*
* @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 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 );
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 setting block from I/O buffer
*
* @v iobuf I/O buffer
* @ret dhcpset DHCP settings block
*
* This function takes ownership of the I/O buffer. Future accesses
* must be via the @c dhcpset data structure.
*/
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 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;
}

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

View 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

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

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

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