2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 FILE_LICENCE ( GPL2_OR_LATER );
26 #include <ipxe/dhcp.h>
32 * Non-volatile stored options
37 * Calculate checksum over non-volatile stored options
39 * @v nvo Non-volatile options block
42 static unsigned int nvo_checksum ( struct nvo_block *nvo ) {
43 uint8_t *data = nvo->data;
47 for ( i = 0 ; i < nvo->len ; i++ ) {
54 * Reallocate non-volatile stored options block
56 * @v nvo Non-volatile options block
58 * @ret rc Return status code
60 static int nvo_realloc ( struct nvo_block *nvo, size_t len ) {
64 new_data = realloc ( nvo->data, len );
66 DBGC ( nvo, "NVO %p could not allocate %zd bytes\n",
73 /* Update DHCP option block */
75 nvo->dhcpopts.data = ( nvo->data + 1 /* checksum */ );
76 nvo->dhcpopts.alloc_len = ( len - 1 /* checksum */ );
78 nvo->dhcpopts.data = NULL;
79 nvo->dhcpopts.used_len = 0;
80 nvo->dhcpopts.alloc_len = 0;
87 * Reallocate non-volatile stored options DHCP option block
89 * @v options DHCP option block
91 * @ret rc Return status code
93 static int nvo_realloc_dhcpopt ( struct dhcp_options *options, size_t len ) {
94 struct nvo_block *nvo =
95 container_of ( options, struct nvo_block, dhcpopts );
98 /* Refuse to reallocate if we have no way to resize the block */
100 return dhcpopt_no_realloc ( options, len );
102 /* Allow one byte for the checksum (if any data is present) */
106 /* Resize underlying non-volatile options block */
107 if ( ( rc = nvo->resize ( nvo, len ) ) != 0 ) {
108 DBGC ( nvo, "NVO %p could not resize to %zd bytes: %s\n",
109 nvo, len, strerror ( rc ) );
113 /* Reallocate in-memory options block */
114 if ( ( rc = nvo_realloc ( nvo, len ) ) != 0 )
121 * Load non-volatile stored options from non-volatile storage device
123 * @v nvo Non-volatile options block
124 * @ret rc Return status code
126 static int nvo_load ( struct nvo_block *nvo ) {
127 uint8_t *options_data = nvo->dhcpopts.data;
130 /* Skip reading zero-length NVO fields */
131 if ( nvo->len == 0 ) {
132 DBGC ( nvo, "NVO %p is empty; skipping load\n", nvo );
137 if ( ( rc = nvs_read ( nvo->nvs, nvo->address, nvo->data,
138 nvo->len ) ) != 0 ) {
139 DBGC ( nvo, "NVO %p could not read %zd bytes at %#04x: %s\n",
140 nvo, nvo->len, nvo->address, strerror ( rc ) );
144 /* If checksum fails, or options data starts with a zero,
145 * assume the whole block is invalid. This should capture the
146 * case of random initial contents.
148 if ( ( nvo_checksum ( nvo ) != 0 ) || ( options_data[0] == 0 ) ) {
149 DBGC ( nvo, "NVO %p has checksum %02x and initial byte %02x; "
150 "assuming empty\n", nvo, nvo_checksum ( nvo ),
152 memset ( nvo->data, 0, nvo->len );
155 /* Rescan DHCP option block */
156 dhcpopt_update_used_len ( &nvo->dhcpopts );
158 DBGC ( nvo, "NVO %p loaded from non-volatile storage\n", nvo );
163 * Save non-volatile stored options back to non-volatile storage device
165 * @v nvo Non-volatile options block
166 * @ret rc Return status code
168 static int nvo_save ( struct nvo_block *nvo ) {
169 uint8_t *checksum = nvo->data;
172 /* Recalculate checksum, if applicable */
174 *checksum -= nvo_checksum ( nvo );
177 if ( ( rc = nvs_write ( nvo->nvs, nvo->address, nvo->data,
178 nvo->len ) ) != 0 ) {
179 DBGC ( nvo, "NVO %p could not write %zd bytes at %#04x: %s\n",
180 nvo, nvo->len, nvo->address, strerror ( rc ) );
184 DBGC ( nvo, "NVO %p saved to non-volatile storage\n", nvo );
189 * Check applicability of NVO setting
191 * @v settings Settings block
193 * @ret applies Setting applies within this settings block
195 int nvo_applies ( struct settings *settings __unused,
196 const struct setting *setting ) {
198 return ( ( setting->scope == NULL ) &&
199 dhcpopt_applies ( setting->tag ) );
203 * Store value of NVO setting
205 * @v settings Settings block
206 * @v setting Setting to store
207 * @v data Setting data, or NULL to clear setting
208 * @v len Length of setting data
209 * @ret rc Return status code
211 static int nvo_store ( struct settings *settings, const struct setting *setting,
212 const void *data, size_t len ) {
213 struct nvo_block *nvo =
214 container_of ( settings, struct nvo_block, settings );
217 /* Update stored options */
218 if ( ( rc = dhcpopt_store ( &nvo->dhcpopts, setting->tag,
219 data, len ) ) != 0 ) {
220 DBGC ( nvo, "NVO %p could not store %zd bytes: %s\n",
221 nvo, len, strerror ( rc ) );
225 /* Save updated options to NVS */
226 if ( ( rc = nvo_save ( nvo ) ) != 0 )
233 * Fetch value of NVO setting
235 * @v settings Settings block
236 * @v setting Setting to fetch
237 * @v data Buffer to fill with setting data
238 * @v len Length of buffer
239 * @ret len Length of setting data, or negative error
241 * The actual length of the setting will be returned even if
242 * the buffer was too small.
244 static int nvo_fetch ( struct settings *settings, struct setting *setting,
245 void *data, size_t len ) {
246 struct nvo_block *nvo =
247 container_of ( settings, struct nvo_block, settings );
249 return dhcpopt_fetch ( &nvo->dhcpopts, setting->tag, data, len );
252 /** NVO settings operations */
253 static struct settings_operations nvo_settings_operations = {
254 .applies = nvo_applies,
260 * Initialise non-volatile stored options
262 * @v nvo Non-volatile options block
263 * @v nvs Underlying non-volatile storage device
264 * @v address Address within NVS device
265 * @v len Length of non-volatile options data
266 * @v resize Resize method
267 * @v refcnt Containing object reference counter, or NULL
269 void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
270 size_t address, size_t len,
271 int ( * resize ) ( struct nvo_block *nvo, size_t len ),
272 struct refcnt *refcnt ) {
274 nvo->address = address;
276 nvo->resize = resize;
277 dhcpopt_init ( &nvo->dhcpopts, NULL, 0, nvo_realloc_dhcpopt );
278 settings_init ( &nvo->settings, &nvo_settings_operations,
283 * Register non-volatile stored options
285 * @v nvo Non-volatile options block
286 * @v parent Parent settings block, or NULL
287 * @ret rc Return status code
289 int register_nvo ( struct nvo_block *nvo, struct settings *parent ) {
292 /* Allocate memory for options */
293 if ( ( rc = nvo_realloc ( nvo, nvo->len ) ) != 0 )
296 /* Read data from NVS */
297 if ( ( rc = nvo_load ( nvo ) ) != 0 )
300 /* Register settings */
301 if ( ( rc = register_settings ( &nvo->settings, parent,
302 NVO_SETTINGS_NAME ) ) != 0 )
305 DBGC ( nvo, "NVO %p registered\n", nvo );
310 nvo_realloc ( nvo, 0 );
316 * Unregister non-volatile stored options
318 * @v nvo Non-volatile options block
320 void unregister_nvo ( struct nvo_block *nvo ) {
321 unregister_settings ( &nvo->settings );
322 nvo_realloc ( nvo, 0 );
323 DBGC ( nvo, "NVO %p unregistered\n", nvo );