iPXE
nvo.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3 *
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.
8 *
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.
13 *
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
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stdint.h>
28#include <stdlib.h>
29#include <string.h>
30#include <errno.h>
31#include <ipxe/dhcp.h>
32#include <ipxe/nvs.h>
33#include <ipxe/nvo.h>
34
35/** @file
36 *
37 * Non-volatile stored options
38 *
39 */
40
41/**
42 * Calculate checksum over non-volatile stored options
43 *
44 * @v nvo Non-volatile options block
45 * @ret sum Checksum
46 */
47static unsigned int nvo_checksum ( struct nvo_block *nvo ) {
48 uint8_t *data = nvo->data;
49 uint8_t sum = 0;
50 unsigned int i;
51
52 for ( i = 0 ; i < nvo->len ; i++ ) {
53 sum += *(data++);
54 }
55 return sum;
56}
57
58/**
59 * Reallocate non-volatile stored options block
60 *
61 * @v nvo Non-volatile options block
62 * @v len New length
63 * @ret rc Return status code
64 */
65static int nvo_realloc ( struct nvo_block *nvo, size_t len ) {
66 void *new_data;
67
68 /* Reallocate data */
69 new_data = realloc ( nvo->data, len );
70 if ( ! new_data ) {
71 DBGC ( nvo, "NVO %p could not allocate %zd bytes\n",
72 nvo, len );
73 return -ENOMEM;
74 }
75 nvo->data = new_data;
76 nvo->len = len;
77
78 /* Update DHCP option block */
79 if ( len ) {
80 nvo->dhcpopts.data = ( nvo->data + 1 /* checksum */ );
81 nvo->dhcpopts.alloc_len = ( len - 1 /* checksum */ );
82 } else {
83 nvo->dhcpopts.data = NULL;
84 nvo->dhcpopts.used_len = 0;
85 nvo->dhcpopts.alloc_len = 0;
86 }
87
88 return 0;
89}
90
91/**
92 * Reallocate non-volatile stored options DHCP option block
93 *
94 * @v options DHCP option block
95 * @v len New length
96 * @ret rc Return status code
97 */
98static int nvo_realloc_dhcpopt ( struct dhcp_options *options, size_t len ) {
99 struct nvo_block *nvo =
101 int rc;
102
103 /* Refuse to reallocate if we have no way to resize the block */
104 if ( ! nvo->resize )
105 return dhcpopt_no_realloc ( options, len );
106
107 /* Allow one byte for the checksum (if any data is present) */
108 if ( len )
109 len += 1;
110
111 /* Resize underlying non-volatile options block */
112 if ( ( rc = nvo->resize ( nvo, len ) ) != 0 ) {
113 DBGC ( nvo, "NVO %p could not resize to %zd bytes: %s\n",
114 nvo, len, strerror ( rc ) );
115 return rc;
116 }
117
118 /* Reallocate in-memory options block */
119 if ( ( rc = nvo_realloc ( nvo, len ) ) != 0 )
120 return rc;
121
122 return 0;
123}
124
125/**
126 * Load non-volatile stored options from non-volatile storage device
127 *
128 * @v nvo Non-volatile options block
129 * @ret rc Return status code
130 */
131static int nvo_load ( struct nvo_block *nvo ) {
132 uint8_t *options_data = nvo->dhcpopts.data;
133 int rc;
134
135 /* Skip reading zero-length NVO fields */
136 if ( nvo->len == 0 ) {
137 DBGC ( nvo, "NVO %p is empty; skipping load\n", nvo );
138 return 0;
139 }
140
141 /* Read data */
142 if ( ( rc = nvs_read ( nvo->nvs, nvo->address, nvo->data,
143 nvo->len ) ) != 0 ) {
144 DBGC ( nvo, "NVO %p could not read %zd bytes at %#04x: %s\n",
145 nvo, nvo->len, nvo->address, strerror ( rc ) );
146 return rc;
147 }
148
149 /* If checksum fails, or options data starts with a zero,
150 * assume the whole block is invalid. This should capture the
151 * case of random initial contents.
152 */
153 if ( ( nvo_checksum ( nvo ) != 0 ) || ( options_data[0] == 0 ) ) {
154 DBGC ( nvo, "NVO %p has checksum %02x and initial byte %02x; "
155 "assuming empty\n", nvo, nvo_checksum ( nvo ),
156 options_data[0] );
157 memset ( nvo->data, 0, nvo->len );
158 }
159
160 /* Rescan DHCP option block */
162
163 DBGC ( nvo, "NVO %p loaded from non-volatile storage\n", nvo );
164 return 0;
165}
166
167/**
168 * Save non-volatile stored options back to non-volatile storage device
169 *
170 * @v nvo Non-volatile options block
171 * @ret rc Return status code
172 */
173static int nvo_save ( struct nvo_block *nvo ) {
174 uint8_t *checksum = nvo->data;
175 int rc;
176
177 /* Recalculate checksum, if applicable */
178 if ( nvo->len > 0 )
179 *checksum -= nvo_checksum ( nvo );
180
181 /* Write data */
182 if ( ( rc = nvs_write ( nvo->nvs, nvo->address, nvo->data,
183 nvo->len ) ) != 0 ) {
184 DBGC ( nvo, "NVO %p could not write %zd bytes at %#04x: %s\n",
185 nvo, nvo->len, nvo->address, strerror ( rc ) );
186 return rc;
187 }
188
189 DBGC ( nvo, "NVO %p saved to non-volatile storage\n", nvo );
190 return 0;
191}
192
193/**
194 * Check applicability of NVO setting
195 *
196 * @v settings Settings block
197 * @v setting Setting
198 * @ret applies Setting applies within this settings block
199 */
201 const struct setting *setting ) {
202
203 return ( ( setting->scope == NULL ) &&
205}
206
207/**
208 * Store value of NVO setting
209 *
210 * @v settings Settings block
211 * @v setting Setting to store
212 * @v data Setting data, or NULL to clear setting
213 * @v len Length of setting data
214 * @ret rc Return status code
215 */
216static int nvo_store ( struct settings *settings, const struct setting *setting,
217 const void *data, size_t len ) {
218 struct nvo_block *nvo =
220 int rc;
221
222 /* Update stored options */
223 if ( ( rc = dhcpopt_store ( &nvo->dhcpopts, setting->tag,
224 data, len ) ) != 0 ) {
225 DBGC ( nvo, "NVO %p could not store %zd bytes: %s\n",
226 nvo, len, strerror ( rc ) );
227 return rc;
228 }
229
230 /* Save updated options to NVS */
231 if ( ( rc = nvo_save ( nvo ) ) != 0 )
232 return rc;
233
234 return 0;
235}
236
237/**
238 * Fetch value of NVO setting
239 *
240 * @v settings Settings block
241 * @v setting Setting to fetch
242 * @v data Buffer to fill with setting data
243 * @v len Length of buffer
244 * @ret len Length of setting data, or negative error
245 *
246 * The actual length of the setting will be returned even if
247 * the buffer was too small.
248 */
249static int nvo_fetch ( struct settings *settings, struct setting *setting,
250 void *data, size_t len ) {
251 struct nvo_block *nvo =
253
254 return dhcpopt_fetch ( &nvo->dhcpopts, setting->tag, data, len );
255}
256
257/** NVO settings operations */
259 .applies = nvo_applies,
260 .store = nvo_store,
261 .fetch = nvo_fetch,
262};
263
264/**
265 * Initialise non-volatile stored options
266 *
267 * @v nvo Non-volatile options block
268 * @v nvs Underlying non-volatile storage device
269 * @v address Address within NVS device
270 * @v len Length of non-volatile options data
271 * @v resize Resize method
272 * @v refcnt Containing object reference counter, or NULL
273 */
274void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
275 size_t address, size_t len,
276 int ( * resize ) ( struct nvo_block *nvo, size_t len ),
277 struct refcnt *refcnt ) {
278 nvo->nvs = nvs;
279 nvo->address = address;
280 nvo->len = len;
281 nvo->resize = resize;
284 refcnt, NULL );
285}
286
287/**
288 * Register non-volatile stored options
289 *
290 * @v nvo Non-volatile options block
291 * @v parent Parent settings block, or NULL
292 * @ret rc Return status code
293 */
294int register_nvo ( struct nvo_block *nvo, struct settings *parent ) {
295 int rc;
296
297 /* Allocate memory for options */
298 if ( ( rc = nvo_realloc ( nvo, nvo->len ) ) != 0 )
299 goto err_realloc;
300
301 /* Read data from NVS */
302 if ( ( rc = nvo_load ( nvo ) ) != 0 )
303 goto err_load;
304
305 /* Register settings */
306 if ( ( rc = register_settings ( &nvo->settings, parent,
307 NVO_SETTINGS_NAME ) ) != 0 )
308 goto err_register;
309
310 DBGC ( nvo, "NVO %p registered\n", nvo );
311 return 0;
312
313 err_register:
314 err_load:
315 nvo_realloc ( nvo, 0 );
316 err_realloc:
317 return rc;
318}
319
320/**
321 * Unregister non-volatile stored options
322 *
323 * @v nvo Non-volatile options block
324 */
325void unregister_nvo ( struct nvo_block *nvo ) {
327 nvo_realloc ( nvo, 0 );
328 DBGC ( nvo, "NVO %p unregistered\n", nvo );
329}
static int options
Definition 3c515.c:286
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned char uint8_t
Definition stdint.h:10
int dhcpopt_no_realloc(struct dhcp_options *options, size_t len)
Refuse to reallocate DHCP option block.
Definition dhcpopts.c:185
int dhcpopt_applies(unsigned int tag)
Check applicability of DHCP option setting.
Definition dhcpopts.c:360
void dhcpopt_init(struct dhcp_options *options, void *data, size_t alloc_len, int(*realloc)(struct dhcp_options *options, size_t len))
Initialise prepopulated block of DHCP options.
Definition dhcpopts.c:452
int dhcpopt_fetch(struct dhcp_options *options, unsigned int tag, void *data, size_t len)
Fetch value of DHCP option setting.
Definition dhcpopts.c:394
void dhcpopt_update_used_len(struct dhcp_options *options)
Recalculate length of DHCP options block.
Definition dhcpopts.c:421
int dhcpopt_store(struct dhcp_options *options, unsigned int tag, const void *data, size_t len)
Store value of DHCP option setting.
Definition dhcpopts.c:375
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint64_t address
Base address.
Definition ena.h:13
Error codes.
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOMEM
Not enough space.
Definition errno.h:535
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
Dynamic Host Configuration Protocol.
static void settings_init(struct settings *settings, struct settings_operations *op, struct refcnt *refcnt, const struct settings_scope *default_scope)
Initialise a settings block.
Definition settings.h:503
String functions.
void * memset(void *dest, int character, size_t len) __nonnull
void * realloc(void *old_ptr, size_t new_size)
Reallocate memory.
Definition malloc.c:607
void nvo_init(struct nvo_block *nvo, struct nvs_device *nvs, size_t address, size_t len, int(*resize)(struct nvo_block *nvo, size_t len), struct refcnt *refcnt)
Initialise non-volatile stored options.
Definition nvo.c:274
static int nvo_realloc(struct nvo_block *nvo, size_t len)
Reallocate non-volatile stored options block.
Definition nvo.c:65
static unsigned int nvo_checksum(struct nvo_block *nvo)
Calculate checksum over non-volatile stored options.
Definition nvo.c:47
void unregister_nvo(struct nvo_block *nvo)
Unregister non-volatile stored options.
Definition nvo.c:325
static int nvo_realloc_dhcpopt(struct dhcp_options *options, size_t len)
Reallocate non-volatile stored options DHCP option block.
Definition nvo.c:98
int register_nvo(struct nvo_block *nvo, struct settings *parent)
Register non-volatile stored options.
Definition nvo.c:294
static int nvo_load(struct nvo_block *nvo)
Load non-volatile stored options from non-volatile storage device.
Definition nvo.c:131
static int nvo_fetch(struct settings *settings, struct setting *setting, void *data, size_t len)
Fetch value of NVO setting.
Definition nvo.c:249
static int nvo_store(struct settings *settings, const struct setting *setting, const void *data, size_t len)
Store value of NVO setting.
Definition nvo.c:216
int nvo_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of NVO setting.
Definition nvo.c:200
static struct settings_operations nvo_settings_operations
NVO settings operations.
Definition nvo.c:258
static int nvo_save(struct nvo_block *nvo)
Save non-volatile stored options back to non-volatile storage device.
Definition nvo.c:173
Non-volatile stored options.
#define NVO_SETTINGS_NAME
Name of non-volatile options settings block.
Definition nvo.h:47
int nvs_read(struct nvs_device *nvs, unsigned int address, void *data, size_t len)
Read from non-volatile storage device.
Definition nvs.c:76
int nvs_write(struct nvs_device *nvs, unsigned int address, const void *data, size_t len)
Write to non-volatile storage device.
Definition nvs.c:141
Non-volatile storage.
uint8_t checksum
Checksum.
Definition pnpbios.c:12
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition settings.c:476
void unregister_settings(struct settings *settings)
Unregister settings block.
Definition settings.c:515
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
A DHCP options block.
Definition dhcpopts.h:16
void * data
Option block raw data.
Definition dhcpopts.h:18
size_t used_len
Option block used length.
Definition dhcpopts.h:20
size_t alloc_len
Option block allocated length.
Definition dhcpopts.h:22
A block of non-volatile stored options.
Definition nvo.h:23
size_t len
Length of options data.
Definition nvo.h:31
int(* resize)(struct nvo_block *nvo, size_t len)
Resize non-volatile stored option block.
Definition nvo.h:41
struct settings settings
Settings block.
Definition nvo.h:25
unsigned int address
Address within NVS device.
Definition nvo.h:29
struct dhcp_options dhcpopts
DHCP options block.
Definition nvo.h:43
void * data
Option-containing data.
Definition nvo.h:33
struct nvs_device * nvs
Underlying non-volatile storage device.
Definition nvo.h:27
A non-volatile storage device.
Definition nvs.h:16
A reference counter.
Definition refcnt.h:27
A setting.
Definition settings.h:24
const struct settings_scope * scope
Setting scope (or NULL)
Definition settings.h:50
uint64_t tag
Setting tag, if applicable.
Definition settings.h:44
Settings block operations.
Definition settings.h:86
A settings block.
Definition settings.h:133