mirror of https://github.com/ipxe/ipxe.git
[settings] Allow for arbitrarily-named settings
This provides a mechanism for using arbitrarily-named variables within gPXE, using the existing syntax for settings.pull/1/head
parent
822b3b53f4
commit
3c06277bbb
|
@ -41,65 +41,194 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* Registered settings blocks
|
* Generic settings blocks
|
||||||
*
|
*
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store value of simple setting
|
* A generic setting
|
||||||
*
|
*
|
||||||
* @v options DHCP option block
|
*/
|
||||||
|
struct generic_setting {
|
||||||
|
/** List of generic settings */
|
||||||
|
struct list_head list;
|
||||||
|
/** Setting */
|
||||||
|
struct setting setting;
|
||||||
|
/** Size of setting name */
|
||||||
|
size_t name_len;
|
||||||
|
/** Size of setting data */
|
||||||
|
size_t data_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get generic setting name
|
||||||
|
*
|
||||||
|
* @v generic Generic setting
|
||||||
|
* @ret name Generic setting name
|
||||||
|
*/
|
||||||
|
static inline void * generic_setting_name ( struct generic_setting *generic ) {
|
||||||
|
return ( ( ( void * ) generic ) + sizeof ( *generic ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get generic setting data
|
||||||
|
*
|
||||||
|
* @v generic Generic setting
|
||||||
|
* @ret data Generic setting data
|
||||||
|
*/
|
||||||
|
static inline void * generic_setting_data ( struct generic_setting *generic ) {
|
||||||
|
return ( ( ( void * ) generic ) + sizeof ( *generic ) +
|
||||||
|
generic->name_len );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find generic setting
|
||||||
|
*
|
||||||
|
* @v generics Generic settings block
|
||||||
|
* @v setting Setting to find
|
||||||
|
* @ret generic Generic setting, or NULL
|
||||||
|
*/
|
||||||
|
static struct generic_setting *
|
||||||
|
find_generic_setting ( struct generic_settings *generics,
|
||||||
|
struct setting *setting ) {
|
||||||
|
struct generic_setting *generic;
|
||||||
|
|
||||||
|
list_for_each_entry ( generic, &generics->list, list ) {
|
||||||
|
if ( setting_cmp ( &generic->setting, setting ) == 0 )
|
||||||
|
return generic;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store value of generic setting
|
||||||
|
*
|
||||||
|
* @v settings Settings block
|
||||||
* @v setting Setting to store
|
* @v setting Setting to store
|
||||||
* @v data Setting data, or NULL to clear setting
|
* @v data Setting data, or NULL to clear setting
|
||||||
* @v len Length of setting data
|
* @v len Length of setting data
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
int simple_settings_store ( struct settings *settings, struct setting *setting,
|
int generic_settings_store ( struct settings *settings,
|
||||||
const void *data, size_t len ) {
|
struct setting *setting,
|
||||||
struct simple_settings *simple =
|
const void *data, size_t len ) {
|
||||||
container_of ( settings, struct simple_settings, settings );
|
struct generic_settings *generics =
|
||||||
return dhcpopt_extensible_store ( &simple->dhcpopts, setting->tag,
|
container_of ( settings, struct generic_settings, settings );
|
||||||
data, len );
|
struct generic_setting *old;
|
||||||
|
struct generic_setting *new = NULL;
|
||||||
|
size_t name_len;
|
||||||
|
|
||||||
|
/* Identify existing generic setting, if any */
|
||||||
|
old = find_generic_setting ( generics, setting );
|
||||||
|
|
||||||
|
/* Create new generic setting, if required */
|
||||||
|
if ( len ) {
|
||||||
|
/* Allocate new generic setting */
|
||||||
|
name_len = ( strlen ( setting->name ) + 1 );
|
||||||
|
new = zalloc ( sizeof ( *new ) + name_len + len );
|
||||||
|
if ( ! new )
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* Populate new generic setting */
|
||||||
|
new->name_len = name_len;
|
||||||
|
new->data_len = len;
|
||||||
|
memcpy ( &new->setting, setting, sizeof ( new->setting ) );
|
||||||
|
new->setting.name = generic_setting_name ( new );
|
||||||
|
memcpy ( generic_setting_name ( new ),
|
||||||
|
setting->name, name_len );
|
||||||
|
memcpy ( generic_setting_data ( new ), data, len );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete existing generic setting, if any */
|
||||||
|
if ( old ) {
|
||||||
|
list_del ( &old->list );
|
||||||
|
free ( old );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add new setting to list, if any */
|
||||||
|
if ( new )
|
||||||
|
list_add ( &new->list, &generics->list );
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch value of simple setting
|
* Fetch value of generic setting
|
||||||
*
|
*
|
||||||
* @v options DHCP option block
|
* @v settings Settings block
|
||||||
* @v setting Setting to fetch
|
* @v setting Setting to fetch
|
||||||
* @v data Buffer to fill with setting data
|
* @v data Buffer to fill with setting data
|
||||||
* @v len Length of buffer
|
* @v len Length of buffer
|
||||||
* @ret len Length of setting data, or negative error
|
* @ret len Length of setting data, or negative error
|
||||||
*/
|
*/
|
||||||
int simple_settings_fetch ( struct settings *settings, struct setting *setting,
|
int generic_settings_fetch ( struct settings *settings,
|
||||||
void *data, size_t len ) {
|
struct setting *setting,
|
||||||
struct simple_settings *simple =
|
void *data, size_t len ) {
|
||||||
container_of ( settings, struct simple_settings, settings );
|
struct generic_settings *generics =
|
||||||
return dhcpopt_fetch ( &simple->dhcpopts, setting->tag, data, len );
|
container_of ( settings, struct generic_settings, settings );
|
||||||
|
struct generic_setting *generic;
|
||||||
|
|
||||||
|
/* Find generic setting */
|
||||||
|
generic = find_generic_setting ( generics, setting );
|
||||||
|
if ( ! generic )
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
/* Copy out generic setting data */
|
||||||
|
if ( len > generic->data_len )
|
||||||
|
len = generic->data_len;
|
||||||
|
memcpy ( data, generic_setting_data ( generic ), len );
|
||||||
|
return generic->data_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Simple settings operations */
|
/**
|
||||||
struct settings_operations simple_settings_operations = {
|
* Clear generic settings block
|
||||||
.store = simple_settings_store,
|
*
|
||||||
.fetch = simple_settings_fetch,
|
* @v settings Settings block
|
||||||
|
*/
|
||||||
|
void generic_settings_clear ( struct settings *settings ) {
|
||||||
|
struct generic_settings *generics =
|
||||||
|
container_of ( settings, struct generic_settings, settings );
|
||||||
|
struct generic_setting *generic;
|
||||||
|
struct generic_setting *tmp;
|
||||||
|
|
||||||
|
list_for_each_entry_safe ( generic, tmp, &generics->list, list ) {
|
||||||
|
list_del ( &generic->list );
|
||||||
|
free ( generic );
|
||||||
|
}
|
||||||
|
assert ( list_empty ( &generics->list ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Generic settings operations */
|
||||||
|
struct settings_operations generic_settings_operations = {
|
||||||
|
.store = generic_settings_store,
|
||||||
|
.fetch = generic_settings_fetch,
|
||||||
|
.clear = generic_settings_clear,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Root simple settings block */
|
/******************************************************************************
|
||||||
struct simple_settings simple_settings_root = {
|
*
|
||||||
|
* Registered settings blocks
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Root generic settings block */
|
||||||
|
struct generic_settings generic_settings_root = {
|
||||||
.settings = {
|
.settings = {
|
||||||
.refcnt = NULL,
|
.refcnt = NULL,
|
||||||
.name = "",
|
.name = "",
|
||||||
.siblings =
|
.siblings =
|
||||||
LIST_HEAD_INIT ( simple_settings_root.settings.siblings ),
|
LIST_HEAD_INIT ( generic_settings_root.settings.siblings ),
|
||||||
.children =
|
.children =
|
||||||
LIST_HEAD_INIT ( simple_settings_root.settings.children ),
|
LIST_HEAD_INIT ( generic_settings_root.settings.children ),
|
||||||
.op = &simple_settings_operations,
|
.op = &generic_settings_operations,
|
||||||
},
|
},
|
||||||
|
.list = LIST_HEAD_INIT ( generic_settings_root.list ),
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Root settings block */
|
/** Root settings block */
|
||||||
#define settings_root simple_settings_root.settings
|
#define settings_root generic_settings_root.settings
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find child named settings block
|
* Find child named settings block
|
||||||
|
@ -135,7 +264,7 @@ static struct settings * find_child_settings ( struct settings *parent,
|
||||||
static struct settings * autovivify_child_settings ( struct settings *parent,
|
static struct settings * autovivify_child_settings ( struct settings *parent,
|
||||||
const char *name ) {
|
const char *name ) {
|
||||||
struct {
|
struct {
|
||||||
struct simple_settings simple;
|
struct generic_settings generic;
|
||||||
char name[ strlen ( name ) + 1 /* NUL */ ];
|
char name[ strlen ( name ) + 1 /* NUL */ ];
|
||||||
} *new_child;
|
} *new_child;
|
||||||
struct settings *settings;
|
struct settings *settings;
|
||||||
|
@ -144,7 +273,7 @@ static struct settings * autovivify_child_settings ( struct settings *parent,
|
||||||
if ( ( settings = find_child_settings ( parent, name ) ) != NULL )
|
if ( ( settings = find_child_settings ( parent, name ) ) != NULL )
|
||||||
return settings;
|
return settings;
|
||||||
|
|
||||||
/* Create new simple settings block */
|
/* Create new generic settings block */
|
||||||
new_child = zalloc ( sizeof ( *new_child ) );
|
new_child = zalloc ( sizeof ( *new_child ) );
|
||||||
if ( ! new_child ) {
|
if ( ! new_child ) {
|
||||||
DBGC ( parent, "Settings %p could not create child %s\n",
|
DBGC ( parent, "Settings %p could not create child %s\n",
|
||||||
|
@ -152,12 +281,31 @@ static struct settings * autovivify_child_settings ( struct settings *parent,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memcpy ( new_child->name, name, sizeof ( new_child->name ) );
|
memcpy ( new_child->name, name, sizeof ( new_child->name ) );
|
||||||
simple_settings_init ( &new_child->simple, NULL, new_child->name );
|
generic_settings_init ( &new_child->generic, NULL, new_child->name );
|
||||||
settings = &new_child->simple.settings;
|
settings = &new_child->generic.settings;
|
||||||
register_settings ( settings, parent );
|
register_settings ( settings, parent );
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return settings block name (for debug only)
|
||||||
|
*
|
||||||
|
* @v settings Settings block
|
||||||
|
* @ret name Settings block name
|
||||||
|
*/
|
||||||
|
static const char * settings_name ( struct settings *settings ) {
|
||||||
|
static char buf[64];
|
||||||
|
char tmp[ sizeof ( buf ) ];
|
||||||
|
int count;
|
||||||
|
|
||||||
|
for ( count = 0 ; settings ; settings = settings->parent ) {
|
||||||
|
memcpy ( tmp, buf, sizeof ( tmp ) );
|
||||||
|
snprintf ( buf, sizeof ( buf ), "%s%c%s", settings->name,
|
||||||
|
( count++ ? '.' : '\0' ), tmp );
|
||||||
|
}
|
||||||
|
return ( buf + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse settings block name
|
* Parse settings block name
|
||||||
*
|
*
|
||||||
|
@ -284,7 +432,8 @@ int register_settings ( struct settings *settings, struct settings *parent ) {
|
||||||
ref_get ( parent->refcnt );
|
ref_get ( parent->refcnt );
|
||||||
settings->parent = parent;
|
settings->parent = parent;
|
||||||
list_add_tail ( &settings->siblings, &parent->children );
|
list_add_tail ( &settings->siblings, &parent->children );
|
||||||
DBGC ( settings, "Settings %p registered\n", settings );
|
DBGC ( settings, "Settings %p (\"%s\") registered\n",
|
||||||
|
settings, settings_name ( settings ) );
|
||||||
|
|
||||||
/* Fix up settings priority */
|
/* Fix up settings priority */
|
||||||
reprioritise_settings ( settings );
|
reprioritise_settings ( settings );
|
||||||
|
@ -302,12 +451,14 @@ int register_settings ( struct settings *settings, struct settings *parent ) {
|
||||||
*/
|
*/
|
||||||
void unregister_settings ( struct settings *settings ) {
|
void unregister_settings ( struct settings *settings ) {
|
||||||
|
|
||||||
|
DBGC ( settings, "Settings %p (\"%s\") unregistered\n",
|
||||||
|
settings, settings_name ( settings ) );
|
||||||
|
|
||||||
/* Remove from list of settings */
|
/* Remove from list of settings */
|
||||||
ref_put ( settings->refcnt );
|
ref_put ( settings->refcnt );
|
||||||
ref_put ( settings->parent->refcnt );
|
ref_put ( settings->parent->refcnt );
|
||||||
settings->parent = NULL;
|
settings->parent = NULL;
|
||||||
list_del ( &settings->siblings );
|
list_del ( &settings->siblings );
|
||||||
DBGC ( settings, "Settings %p unregistered\n", settings );
|
|
||||||
|
|
||||||
/* Apply potentially-updated settings */
|
/* Apply potentially-updated settings */
|
||||||
apply_settings();
|
apply_settings();
|
||||||
|
@ -337,6 +488,10 @@ int store_setting ( struct settings *settings, struct setting *setting,
|
||||||
if ( ! settings )
|
if ( ! settings )
|
||||||
settings = &settings_root;
|
settings = &settings_root;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if ( ! settings->op->store )
|
||||||
|
return -ENOTSUP;
|
||||||
|
|
||||||
/* Store setting */
|
/* Store setting */
|
||||||
if ( ( rc = settings->op->store ( settings, setting,
|
if ( ( rc = settings->op->store ( settings, setting,
|
||||||
data, len ) ) != 0 )
|
data, len ) ) != 0 )
|
||||||
|
@ -384,6 +539,10 @@ int fetch_setting ( struct settings *settings, struct setting *setting,
|
||||||
if ( ! settings )
|
if ( ! settings )
|
||||||
settings = &settings_root;
|
settings = &settings_root;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if ( ! settings->op->fetch )
|
||||||
|
return -ENOTSUP;
|
||||||
|
|
||||||
/* Try this block first */
|
/* Try this block first */
|
||||||
if ( ( ret = settings->op->fetch ( settings, setting,
|
if ( ( ret = settings->op->fetch ( settings, setting,
|
||||||
data, len ) ) >= 0 )
|
data, len ) ) >= 0 )
|
||||||
|
@ -599,6 +758,16 @@ int fetch_uuid_setting ( struct settings *settings, struct setting *setting,
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear settings block
|
||||||
|
*
|
||||||
|
* @v settings Settings block
|
||||||
|
*/
|
||||||
|
void clear_settings ( struct settings *settings ) {
|
||||||
|
if ( settings->op->clear )
|
||||||
|
settings->op->clear ( settings );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare two settings
|
* Compare two settings
|
||||||
*
|
*
|
||||||
|
@ -662,6 +831,26 @@ static struct setting * find_setting ( const char *name ) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse setting name as tag number
|
||||||
|
*
|
||||||
|
* @v name Name
|
||||||
|
* @ret tag Tag number, or 0 if not a valid number
|
||||||
|
*/
|
||||||
|
static unsigned int parse_setting_tag ( const char *name ) {
|
||||||
|
char *tmp = ( ( char * ) name );
|
||||||
|
unsigned int tag = 0;
|
||||||
|
|
||||||
|
while ( 1 ) {
|
||||||
|
tag = ( ( tag << 8 ) | strtoul ( tmp, &tmp, 0 ) );
|
||||||
|
if ( *tmp == 0 )
|
||||||
|
return tag;
|
||||||
|
if ( *tmp != '.' )
|
||||||
|
return 0;
|
||||||
|
tmp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find setting type
|
* Find setting type
|
||||||
*
|
*
|
||||||
|
@ -685,31 +874,35 @@ static struct setting_type * find_setting_type ( const char *name ) {
|
||||||
* @v get_child Function to find or create child settings block
|
* @v get_child Function to find or create child settings block
|
||||||
* @v settings Settings block to fill in
|
* @v settings Settings block to fill in
|
||||||
* @v setting Setting to fill in
|
* @v setting Setting to fill in
|
||||||
|
* @v tmp_name Buffer for copy of setting name
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*
|
*
|
||||||
* Interprets a name of the form
|
* Interprets a name of the form
|
||||||
* "[settings_name/]tag_name[:type_name]" and fills in the appropriate
|
* "[settings_name/]tag_name[:type_name]" and fills in the appropriate
|
||||||
* fields.
|
* fields.
|
||||||
|
*
|
||||||
|
* The @c tmp_name buffer must be large enough to hold a copy of the
|
||||||
|
* setting name.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
parse_setting_name ( const char *name,
|
parse_setting_name ( const char *name,
|
||||||
struct settings * ( * get_child ) ( struct settings *,
|
struct settings * ( * get_child ) ( struct settings *,
|
||||||
const char * ),
|
const char * ),
|
||||||
struct settings **settings, struct setting *setting ) {
|
struct settings **settings, struct setting *setting,
|
||||||
char tmp_name[ strlen ( name ) + 1 ];
|
char *tmp_name ) {
|
||||||
char *settings_name;
|
char *settings_name;
|
||||||
char *setting_name;
|
char *setting_name;
|
||||||
char *type_name;
|
char *type_name;
|
||||||
struct setting *named_setting;
|
struct setting *named_setting;
|
||||||
char *tmp;
|
|
||||||
|
|
||||||
/* Set defaults */
|
/* Set defaults */
|
||||||
*settings = &settings_root;
|
*settings = &settings_root;
|
||||||
memset ( setting, 0, sizeof ( *setting ) );
|
memset ( setting, 0, sizeof ( *setting ) );
|
||||||
setting->type = &setting_type_hex;
|
setting->name = "";
|
||||||
|
setting->type = &setting_type_string;
|
||||||
|
|
||||||
/* Split name into "[settings_name/]setting_name[:type_name]" */
|
/* Split name into "[settings_name/]setting_name[:type_name]" */
|
||||||
memcpy ( tmp_name, name, sizeof ( tmp_name ) );
|
strcpy ( tmp_name, name );
|
||||||
if ( ( setting_name = strchr ( tmp_name, '/' ) ) != NULL ) {
|
if ( ( setting_name = strchr ( tmp_name, '/' ) ) != NULL ) {
|
||||||
*(setting_name++) = 0;
|
*(setting_name++) = 0;
|
||||||
settings_name = tmp_name;
|
settings_name = tmp_name;
|
||||||
|
@ -730,25 +923,16 @@ parse_setting_name ( const char *name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Identify tag number */
|
/* Identify setting */
|
||||||
if ( ( named_setting = find_setting ( setting_name ) ) != NULL ) {
|
if ( ( named_setting = find_setting ( setting_name ) ) != NULL ) {
|
||||||
|
/* Matches a defined named setting; use that setting */
|
||||||
memcpy ( setting, named_setting, sizeof ( *setting ) );
|
memcpy ( setting, named_setting, sizeof ( *setting ) );
|
||||||
} else {
|
} else if ( ( setting->tag = parse_setting_tag ( setting_name ) ) !=0){
|
||||||
/* Unrecognised name: try to interpret as a tag number */
|
/* Is a valid numeric tag; use the tag */
|
||||||
tmp = setting_name;
|
|
||||||
while ( 1 ) {
|
|
||||||
setting->tag = ( ( setting->tag << 8 ) |
|
|
||||||
strtoul ( tmp, &tmp, 0 ) );
|
|
||||||
if ( *tmp == 0 )
|
|
||||||
break;
|
|
||||||
if ( *tmp != '.' ) {
|
|
||||||
DBG ( "Invalid setting \"%s\" in \"%s\"\n",
|
|
||||||
setting_name, name );
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
tmp++;
|
|
||||||
}
|
|
||||||
setting->tag |= (*settings)->tag_magic;
|
setting->tag |= (*settings)->tag_magic;
|
||||||
|
} else {
|
||||||
|
/* Use the arbitrary name */
|
||||||
|
setting->name = setting_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Identify setting type, if specified */
|
/* Identify setting type, if specified */
|
||||||
|
@ -774,10 +958,11 @@ parse_setting_name ( const char *name,
|
||||||
int storef_named_setting ( const char *name, const char *value ) {
|
int storef_named_setting ( const char *name, const char *value ) {
|
||||||
struct settings *settings;
|
struct settings *settings;
|
||||||
struct setting setting;
|
struct setting setting;
|
||||||
|
char tmp_name[ strlen ( name ) + 1 ];
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if ( ( rc = parse_setting_name ( name, autovivify_child_settings,
|
if ( ( rc = parse_setting_name ( name, autovivify_child_settings,
|
||||||
&settings, &setting ) ) != 0 )
|
&settings, &setting, tmp_name )) != 0)
|
||||||
return rc;
|
return rc;
|
||||||
return storef_setting ( settings, &setting, value );
|
return storef_setting ( settings, &setting, value );
|
||||||
}
|
}
|
||||||
|
@ -793,10 +978,11 @@ int storef_named_setting ( const char *name, const char *value ) {
|
||||||
int fetchf_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;
|
struct settings *settings;
|
||||||
struct setting setting;
|
struct setting setting;
|
||||||
|
char tmp_name[ strlen ( name ) + 1 ];
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if ( ( rc = parse_setting_name ( name, find_child_settings,
|
if ( ( rc = parse_setting_name ( name, find_child_settings,
|
||||||
&settings, &setting ) ) != 0 )
|
&settings, &setting, tmp_name )) != 0)
|
||||||
return rc;
|
return rc;
|
||||||
return fetchf_setting ( settings, &setting, buf, len );
|
return fetchf_setting ( settings, &setting, buf, len );
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,7 @@ struct net_device {
|
||||||
struct net_device_stats rx_stats;
|
struct net_device_stats rx_stats;
|
||||||
|
|
||||||
/** Configuration settings applicable to this device */
|
/** Configuration settings applicable to this device */
|
||||||
struct simple_settings settings;
|
struct generic_settings settings;
|
||||||
|
|
||||||
/** Driver private data */
|
/** Driver private data */
|
||||||
void *priv;
|
void *priv;
|
||||||
|
@ -295,6 +295,7 @@ struct net_device {
|
||||||
|
|
||||||
extern struct list_head net_devices;
|
extern struct list_head net_devices;
|
||||||
extern struct net_device_operations null_netdev_operations;
|
extern struct net_device_operations null_netdev_operations;
|
||||||
|
extern struct settings_operations netdev_settings_operations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise a network device
|
* Initialise a network device
|
||||||
|
@ -385,6 +386,20 @@ netdev_settings ( struct net_device *netdev ) {
|
||||||
return &netdev->settings.settings;
|
return &netdev->settings.settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise a per-netdevice configuration settings block
|
||||||
|
*
|
||||||
|
* @v generics Generic settings block
|
||||||
|
* @v refcnt Containing object reference counter, or NULL
|
||||||
|
* @v name Settings block name
|
||||||
|
*/
|
||||||
|
static inline __attribute__ (( always_inline )) void
|
||||||
|
netdev_settings_init ( struct net_device *netdev ) {
|
||||||
|
generic_settings_init ( &netdev->settings,
|
||||||
|
&netdev->refcnt, netdev->name );
|
||||||
|
netdev->settings.settings.op = &netdev_settings_operations;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark network device as having link up
|
* Mark network device as having link up
|
||||||
*
|
*
|
||||||
|
@ -440,8 +455,6 @@ extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||||
extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
|
extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||||
uint16_t net_proto, const void *ll_source );
|
uint16_t net_proto, const void *ll_source );
|
||||||
|
|
||||||
extern struct settings_operations netdev_settings_operations;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complete network transmission
|
* Complete network transmission
|
||||||
*
|
*
|
||||||
|
|
|
@ -13,7 +13,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
#include <gpxe/tables.h>
|
#include <gpxe/tables.h>
|
||||||
#include <gpxe/list.h>
|
#include <gpxe/list.h>
|
||||||
#include <gpxe/refcnt.h>
|
#include <gpxe/refcnt.h>
|
||||||
#include <gpxe/dhcpopts.h>
|
|
||||||
|
|
||||||
struct settings;
|
struct settings;
|
||||||
struct in_addr;
|
struct in_addr;
|
||||||
|
@ -69,6 +68,11 @@ struct settings_operations {
|
||||||
*/
|
*/
|
||||||
int ( * fetch ) ( struct settings *settings, struct setting *setting,
|
int ( * fetch ) ( struct settings *settings, struct setting *setting,
|
||||||
void *data, size_t len );
|
void *data, size_t len );
|
||||||
|
/** Clear settings block
|
||||||
|
*
|
||||||
|
* @v settings Settings block
|
||||||
|
*/
|
||||||
|
void ( * clear ) ( struct settings *settings );
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A settings block */
|
/** A settings block */
|
||||||
|
@ -154,23 +158,24 @@ struct settings_applicator {
|
||||||
#define __settings_applicator __table_entry ( SETTINGS_APPLICATORS, 01 )
|
#define __settings_applicator __table_entry ( SETTINGS_APPLICATORS, 01 )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple settings block
|
* A generic settings block
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct simple_settings {
|
struct generic_settings {
|
||||||
/** Settings block */
|
/** Settings block */
|
||||||
struct settings settings;
|
struct settings settings;
|
||||||
/** DHCP options */
|
/** List of generic settings */
|
||||||
struct dhcp_options dhcpopts;
|
struct list_head list;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct settings_operations simple_settings_operations;
|
extern struct settings_operations generic_settings_operations;
|
||||||
extern int simple_settings_store ( struct settings *settings,
|
extern int generic_settings_store ( struct settings *settings,
|
||||||
struct setting *setting,
|
struct setting *setting,
|
||||||
const void *data, size_t len );
|
const void *data, size_t len );
|
||||||
extern int simple_settings_fetch ( struct settings *settings,
|
extern int generic_settings_fetch ( struct settings *settings,
|
||||||
struct setting *setting,
|
struct setting *setting,
|
||||||
void *data, size_t len );
|
void *data, size_t len );
|
||||||
|
extern void generic_settings_clear ( struct settings *settings );
|
||||||
|
|
||||||
extern int register_settings ( struct settings *settings,
|
extern int register_settings ( struct settings *settings,
|
||||||
struct settings *parent );
|
struct settings *parent );
|
||||||
|
@ -201,6 +206,7 @@ extern unsigned long fetch_uintz_setting ( struct settings *settings,
|
||||||
struct setting *setting );
|
struct setting *setting );
|
||||||
extern int fetch_uuid_setting ( struct settings *settings,
|
extern int fetch_uuid_setting ( struct settings *settings,
|
||||||
struct setting *setting, union uuid *uuid );
|
struct setting *setting, union uuid *uuid );
|
||||||
|
extern void clear_settings ( struct settings *settings );
|
||||||
extern int setting_cmp ( struct setting *a, struct setting *b );
|
extern int setting_cmp ( struct setting *a, struct setting *b );
|
||||||
|
|
||||||
extern struct settings * find_settings ( const char *name );
|
extern struct settings * find_settings ( const char *name );
|
||||||
|
@ -263,15 +269,16 @@ static inline void settings_init ( struct settings *settings,
|
||||||
/**
|
/**
|
||||||
* Initialise a settings block
|
* Initialise a settings block
|
||||||
*
|
*
|
||||||
* @v simple Simple settings block
|
* @v generics Generic settings block
|
||||||
* @v refcnt Containing object reference counter, or NULL
|
* @v refcnt Containing object reference counter, or NULL
|
||||||
* @v name Settings block name
|
* @v name Settings block name
|
||||||
*/
|
*/
|
||||||
static inline void simple_settings_init ( struct simple_settings *simple,
|
static inline void generic_settings_init ( struct generic_settings *generics,
|
||||||
struct refcnt *refcnt,
|
struct refcnt *refcnt,
|
||||||
const char *name ) {
|
const char *name ) {
|
||||||
settings_init ( &simple->settings, &simple_settings_operations,
|
settings_init ( &generics->settings, &generic_settings_operations,
|
||||||
refcnt, name, 0 );
|
refcnt, name, 0 );
|
||||||
|
INIT_LIST_HEAD ( &generics->list );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -63,22 +63,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
( (_type) << 16 ) | \
|
( (_type) << 16 ) | \
|
||||||
( offsetof ( _structure, _field ) << 8 ) )
|
( offsetof ( _structure, _field ) << 8 ) )
|
||||||
|
|
||||||
/**
|
|
||||||
* Store value of SMBIOS 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 smbios_store ( struct settings *settings __unused,
|
|
||||||
struct setting *setting __unused,
|
|
||||||
const void *data __unused, size_t len __unused ) {
|
|
||||||
/* Cannot write data into SMBIOS */
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch value of SMBIOS setting
|
* Fetch value of SMBIOS setting
|
||||||
*
|
*
|
||||||
|
@ -135,7 +119,6 @@ static int smbios_fetch ( struct settings *settings __unused,
|
||||||
|
|
||||||
/** SMBIOS settings operations */
|
/** SMBIOS settings operations */
|
||||||
static struct settings_operations smbios_settings_operations = {
|
static struct settings_operations smbios_settings_operations = {
|
||||||
.store = smbios_store,
|
|
||||||
.fetch = smbios_fetch,
|
.fetch = smbios_fetch,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -56,9 +56,9 @@ static int netdev_store ( struct settings *settings, struct setting *setting,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
memcpy ( netdev->ll_addr, data, len );
|
memcpy ( netdev->ll_addr, data, len );
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
|
||||||
return simple_settings_store ( settings, setting, data, len );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return generic_settings_store ( settings, setting, data, len );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,13 +80,23 @@ static int netdev_fetch ( struct settings *settings, struct setting *setting,
|
||||||
len = netdev->ll_protocol->ll_addr_len;
|
len = netdev->ll_protocol->ll_addr_len;
|
||||||
memcpy ( data, netdev->ll_addr, len );
|
memcpy ( data, netdev->ll_addr, len );
|
||||||
return netdev->ll_protocol->ll_addr_len;
|
return netdev->ll_protocol->ll_addr_len;
|
||||||
} else {
|
|
||||||
return simple_settings_fetch ( settings, setting, data, len );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return generic_settings_fetch ( settings, setting, data, len );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear network device settings
|
||||||
|
*
|
||||||
|
* @v settings Settings block
|
||||||
|
*/
|
||||||
|
static void netdev_clear ( struct settings *settings ) {
|
||||||
|
generic_settings_clear ( settings );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Network device configuration settings operations */
|
/** Network device configuration settings operations */
|
||||||
struct settings_operations netdev_settings_operations = {
|
struct settings_operations netdev_settings_operations = {
|
||||||
.store = netdev_store,
|
.store = netdev_store,
|
||||||
.fetch = netdev_fetch,
|
.fetch = netdev_fetch,
|
||||||
|
.clear = netdev_clear,
|
||||||
};
|
};
|
||||||
|
|
|
@ -282,6 +282,7 @@ static void free_netdev ( struct refcnt *refcnt ) {
|
||||||
|
|
||||||
netdev_tx_flush ( netdev );
|
netdev_tx_flush ( netdev );
|
||||||
netdev_rx_flush ( netdev );
|
netdev_rx_flush ( netdev );
|
||||||
|
clear_settings ( netdev_settings ( netdev ) );
|
||||||
free ( netdev );
|
free ( netdev );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,9 +304,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
|
||||||
netdev->refcnt.free = free_netdev;
|
netdev->refcnt.free = free_netdev;
|
||||||
INIT_LIST_HEAD ( &netdev->tx_queue );
|
INIT_LIST_HEAD ( &netdev->tx_queue );
|
||||||
INIT_LIST_HEAD ( &netdev->rx_queue );
|
INIT_LIST_HEAD ( &netdev->rx_queue );
|
||||||
settings_init ( netdev_settings ( netdev ),
|
netdev_settings_init ( netdev );
|
||||||
&netdev_settings_operations, &netdev->refcnt,
|
|
||||||
netdev->name, 0 );
|
|
||||||
netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
|
netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
|
||||||
}
|
}
|
||||||
return netdev;
|
return netdev;
|
||||||
|
|
Loading…
Reference in New Issue