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