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 FILE_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  */
47 static 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  */
65 static 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  */
98 static int nvo_realloc_dhcpopt ( struct dhcp_options *options, size_t len ) {
99  struct nvo_block *nvo =
100  container_of ( options, struct nvo_block, dhcpopts );
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  */
131 static 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  */
173 static 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 ) &&
204  dhcpopt_applies ( setting->tag ) );
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  */
216 static 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  */
249 static 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  */
274 void 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  */
294 int 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  */
325 void unregister_nvo ( struct nvo_block *nvo ) {
326  unregister_settings ( &nvo->settings );
327  nvo_realloc ( nvo, 0 );
328  DBGC ( nvo, "NVO %p unregistered\n", nvo );
329 }
struct dhcp_options dhcpopts
DHCP options block.
Definition: nvo.h:43
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
Dynamic Host Configuration Protocol.
uint8_t checksum
Checksum.
Definition: pnpbios.c:37
int nvo_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of NVO setting.
Definition: nvo.c:200
FILE_SECBOOT(PERMITTED)
void unregister_settings(struct settings *settings)
Unregister settings block.
Definition: settings.c:515
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
Error codes.
A non-volatile storage device.
Definition: nvs.h:16
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:294
#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:141
Non-volatile storage.
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
A reference counter.
Definition: refcnt.h:27
void * data
Option-containing data.
Definition: nvo.h:33
uint64_t tag
Setting tag, if applicable.
Definition: settings.h:44
size_t alloc_len
Option block allocated length.
Definition: dhcpopts.h:22
#define ENOMEM
Not enough space.
Definition: errno.h:535
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:36
static int options
Definition: 3c515.c:286
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
ring len
Length.
Definition: dwmac.h:231
static int nvo_realloc_dhcpopt(struct dhcp_options *options, size_t len)
Reallocate non-volatile stored options DHCP option block.
Definition: nvo.c:98
void unregister_nvo(struct nvo_block *nvo)
Unregister non-volatile stored options.
Definition: nvo.c:325
static int nvo_fetch(struct settings *settings, struct setting *setting, void *data, size_t len)
Fetch value of NVO setting.
Definition: nvo.c:249
Non-volatile stored options.
struct nvs_device * nvs
Underlying non-volatile storage device.
Definition: nvo.h:27
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
A block of non-volatile stored options.
Definition: nvo.h:23
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
int(* resize)(struct nvo_block *nvo, size_t len)
Resize non-volatile stored option block.
Definition: nvo.h:41
Settings block operations.
Definition: settings.h:86
A settings block.
Definition: settings.h:133
unsigned char uint8_t
Definition: stdint.h:10
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
A setting.
Definition: settings.h:24
int dhcpopt_no_realloc(struct dhcp_options *options, size_t len)
Refuse to reallocate DHCP option block.
Definition: dhcpopts.c:185
struct settings settings
Settings block.
Definition: nvo.h:25
unsigned int address
Address within NVS device.
Definition: nvo.h:29
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
static int nvo_realloc(struct nvo_block *nvo, size_t len)
Reallocate non-volatile stored options block.
Definition: nvo.c:65
void * data
Option block raw data.
Definition: dhcpopts.h:18
static int nvo_load(struct nvo_block *nvo)
Load non-volatile stored options from non-volatile storage device.
Definition: nvo.c:131
void dhcpopt_update_used_len(struct dhcp_options *options)
Recalculate length of DHCP options block.
Definition: dhcpopts.c:421
static int nvo_save(struct nvo_block *nvo)
Save non-volatile stored options back to non-volatile storage device.
Definition: nvo.c:173
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:375
static unsigned int nvo_checksum(struct nvo_block *nvo)
Calculate checksum over non-volatile stored options.
Definition: nvo.c:47
void * realloc(void *old_ptr, size_t new_size)
Reallocate memory.
Definition: malloc.c:607
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(* applies)(struct settings *settings, const struct setting *setting)
Check applicability of setting.
Definition: settings.h:99
#define NVO_SETTINGS_NAME
Name of non-volatile options settings block.
Definition: nvo.h:47
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition: settings.c:476
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
static struct settings_operations nvo_settings_operations
NVO settings operations.
Definition: nvo.c:258
const struct settings_scope * scope
Setting scope (or NULL)
Definition: settings.h:50
size_t len
Length of options data.
Definition: nvo.h:31
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
int dhcpopt_applies(unsigned int tag)
Check applicability of DHCP option setting.
Definition: dhcpopts.c:360
String functions.
A DHCP options block.
Definition: dhcpopts.h:16
size_t used_len
Option block used length.
Definition: dhcpopts.h:20
void * memset(void *dest, int character, size_t len) __nonnull