diff options
author | Michael Brown | 2006-12-04 22:46:13 +0100 |
---|---|---|
committer | Michael Brown | 2006-12-04 22:46:13 +0100 |
commit | cc9bcb99a0ac2460dbe8286731e65812fa4ef870 (patch) | |
tree | b2beaafcde77c3502ed7a61dbd139c94455d2e92 /src/core/nvo.c | |
parent | Fixed two logic errors that were cancelling each other out. (diff) | |
download | ipxe-cc9bcb99a0ac2460dbe8286731e65812fa4ef870.tar.gz ipxe-cc9bcb99a0ac2460dbe8286731e65812fa4ef870.tar.xz ipxe-cc9bcb99a0ac2460dbe8286731e65812fa4ef870.zip |
Add the concept of a fragment list for non-volatile stored options.
Diffstat (limited to 'src/core/nvo.c')
-rw-r--r-- | src/core/nvo.c | 129 |
1 files changed, 98 insertions, 31 deletions
diff --git a/src/core/nvo.c b/src/core/nvo.c index 9bd92526..a130329f 100644 --- a/src/core/nvo.c +++ b/src/core/nvo.c @@ -28,79 +28,146 @@ * */ -static size_t nvo_options_len ( struct nvs_options *nvo ) { +/** + * Calculate total length of non-volatile stored options + * + * @v nvo Non-volatile options block + * @ret total_len Total length of all fragments + */ +static size_t nvo_total_len ( struct nvo_block *nvo ) { + struct nvo_fragment *fragment = nvo->fragments; + size_t total_len = 0; + + for ( ; fragment->len ; fragment++ ) { + total_len += fragment->len; + } + + return total_len; +} + +/** + * Read non-volatile stored options from non-volatile storage device + * + * @v nvo Non-volatile options block + * @ret rc Return status code + */ +static int nvo_read ( struct nvo_block *nvo ) { + struct nvo_fragment *fragment = nvo->fragments; + void *data = nvo->options->data; + int rc; + + for ( ; fragment->len ; fragment++ ) { + if ( ( rc = nvs_read ( nvo->nvs, fragment->address, + data, fragment->len ) ) != 0 ) { + DBG ( "NVO %p could not read %zd bytes at %#04x\n", + nvo, fragment->len, fragment->address ); + return rc; + } + data += fragment->len; + } + + return 0; +} + +/** + * Parse stored options + * + * @v nvo Non-volatile options block + * @v total_len Total length of options data + * + * Verifies that the options data is valid, and configures the DHCP + * options block. If the data is not valid, it is replaced with an + * empty options block. + */ +static void nvo_init_dhcp ( struct nvo_block *nvo, size_t total_len ) { + struct dhcp_option_block *options = nvo->options; struct dhcp_option *option; uint8_t sum; unsigned int i; - size_t len; - for ( sum = 0, i = 0 ; i < nvo->nvs->size ; i++ ) { - sum += * ( ( uint8_t * ) ( nvo->options->data + i ) ); + /* Steal one byte for the checksum */ + options->max_len = ( total_len - 1 ); + + /* Verify checksum over whole block */ + for ( sum = 0, i = 0 ; i < total_len ; i++ ) { + sum += * ( ( uint8_t * ) ( options->data + i ) ); } if ( sum != 0 ) { DBG ( "NVO %p has bad checksum %02x; assuming empty\n", nvo, sum ); - return 0; + goto empty; } - option = nvo->options->data; + /* Check that we don't just have a block full of zeroes */ + option = options->data; if ( option->tag == DHCP_PAD ) { DBG ( "NVO %p has bad start; assuming empty\n", nvo ); - return 0; + goto empty; } - option = find_dhcp_option ( nvo->options, DHCP_END ); + /* Search for the DHCP_END tag */ + options->len = options->max_len; + option = find_dhcp_option ( options, DHCP_END ); if ( ! option ) { DBG ( "NVO %p has no end tag; assuming empty\n", nvo ); - return 0; + goto empty; } - len = ( ( void * ) option - nvo->options->data + 1 ); + /* Set correct length of DHCP options */ + options->len = ( ( void * ) option - options->data + 1 ); DBG ( "NVO %p contains %zd bytes of options (maximum %zd)\n", - nvo, len, nvo->nvs->size ); + nvo, options->len, options->max_len ); + return; - return len; + empty: + /* No options found; initialise an empty options block */ + option = options->data; + option->tag = DHCP_END; + options->len = 1; + return; } -int nvo_register ( struct nvs_options *nvo ) { - struct dhcp_option *option; +/** + * Register non-volatile stored options + * + * @v nvo Non-volatile options block + * @ret rc Return status code + */ +int nvo_register ( struct nvo_block *nvo ) { + size_t total_len; int rc; - nvo->options = alloc_dhcp_options ( nvo->nvs->size ); + /* Allocate memory for options and read in from NVS */ + total_len = nvo_total_len ( nvo ); + nvo->options = alloc_dhcp_options ( total_len ); if ( ! nvo->options ) { DBG ( "NVO %p could not allocate %zd bytes\n", - nvo, nvo->nvs->size ); + nvo, total_len ); rc = -ENOMEM; goto err; } - if ( ( rc = nvo->nvs->read ( nvo->nvs, 0, nvo->options->data, - nvo->nvs->size ) ) != 0 ) { - DBG ( "NVO %p could not read [0,%zd)\n", - nvo, nvo->nvs->size ); + if ( ( rc = nvo_read ( nvo ) ) != 0 ) goto err; - } - - nvo->options->len = nvo->options->max_len; - nvo->options->len = nvo_options_len ( nvo ); - if ( ! nvo->options->len ) { - option = nvo->options->data; - option->tag = DHCP_END; - nvo->options->len = 1; - } + /* Verify and register options */ + nvo_init_dhcp ( nvo, total_len ); register_dhcp_options ( nvo->options ); return 0; err: - free_dhcp_options ( nvo->options ); nvo->options = NULL; return rc; } -void nvo_unregister ( struct nvs_options *nvo ) { +/** + * Unregister non-volatile stored options + * + * @v nvo Non-volatile options block + */ +void nvo_unregister ( struct nvo_block *nvo ) { if ( nvo->options ) { unregister_dhcp_options ( nvo->options ); free_dhcp_options ( nvo->options ); |