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., 675 Mass Ave, Cambridge, MA 02139, USA.
19 FILE_LICENCE ( GPL2_OR_LATER
);
25 #include <gpxe/dhcp.h>
31 * Non-volatile stored options
36 * Calculate checksum over non-volatile stored options
38 * @v nvo Non-volatile options block
41 static unsigned int nvo_checksum ( struct nvo_block
*nvo
) {
42 uint8_t *data
= nvo
->data
;
46 for ( i
= 0 ; i
< nvo
->total_len
; i
++ ) {
53 * Load non-volatile stored options from non-volatile storage device
55 * @v nvo Non-volatile options block
56 * @ret rc Return status code
58 static int nvo_load ( struct nvo_block
*nvo
) {
59 void *data
= nvo
->data
;
60 struct nvo_fragment
*frag
;
63 /* Read data a fragment at a time */
64 for ( frag
= nvo
->fragments
; frag
->len
; frag
++ ) {
65 if ( ( rc
= nvs_read ( nvo
->nvs
, frag
->address
, data
,
66 frag
->len
) ) != 0 ) {
67 DBGC ( nvo
, "NVO %p could not read %zd bytes at "
68 "%#04x\n", nvo
, frag
->len
, frag
->address
);
74 DBGC ( nvo
, "NVO %p loaded from non-volatile storage\n", nvo
);
79 * Save non-volatile stored options back to non-volatile storage device
81 * @v nvo Non-volatile options block
82 * @ret rc Return status code
84 static int nvo_save ( struct nvo_block
*nvo
) {
85 void *data
= nvo
->data
;
86 uint8_t *checksum
= data
;
87 struct nvo_fragment
*frag
;
90 /* Recalculate checksum */
91 *checksum
-= nvo_checksum ( nvo
);
93 /* Write data a fragment at a time */
94 for ( frag
= nvo
->fragments
; frag
->len
; frag
++ ) {
95 if ( ( rc
= nvs_write ( nvo
->nvs
, frag
->address
, data
,
96 frag
->len
) ) != 0 ) {
97 DBGC ( nvo
, "NVO %p could not write %zd bytes at "
98 "%#04x\n", nvo
, frag
->len
, frag
->address
);
104 DBGC ( nvo
, "NVO %p saved to non-volatile storage\n", nvo
);
109 * Parse stored options
111 * @v nvo Non-volatile options block
113 * Verifies that the options data is valid, and configures the DHCP
114 * options block. If the data is not valid, it is replaced with an
115 * empty options block.
117 static void nvo_init_dhcpopts ( struct nvo_block
*nvo
) {
118 uint8_t *options_data
;
121 /* Steal one byte for the checksum */
122 options_data
= ( nvo
->data
+ 1 );
123 options_len
= ( nvo
->total_len
- 1 );
125 /* If checksum fails, or options data starts with a zero,
126 * assume the whole block is invalid. This should capture the
127 * case of random initial contents.
129 if ( ( nvo_checksum ( nvo
) != 0 ) || ( options_data
[0] == 0 ) ) {
130 DBGC ( nvo
, "NVO %p has checksum %02x and initial byte %02x; "
131 "assuming empty\n", nvo
, nvo_checksum ( nvo
),
133 memset ( nvo
->data
, 0, nvo
->total_len
);
136 dhcpopt_init ( &nvo
->dhcpopts
, options_data
, options_len
);
140 * Store value of NVO setting
142 * @v settings Settings block
143 * @v setting Setting to store
144 * @v data Setting data, or NULL to clear setting
145 * @v len Length of setting data
146 * @ret rc Return status code
148 static int nvo_store ( struct settings
*settings
, struct setting
*setting
,
149 const void *data
, size_t len
) {
150 struct nvo_block
*nvo
=
151 container_of ( settings
, struct nvo_block
, settings
);
154 /* Update stored options */
155 if ( ( rc
= dhcpopt_store ( &nvo
->dhcpopts
, setting
->tag
,
156 data
, len
) ) != 0 ) {
157 DBGC ( nvo
, "NVO %p could not store %zd bytes: %s\n",
158 nvo
, len
, strerror ( rc
) );
162 /* Save updated options to NVS */
163 if ( ( rc
= nvo_save ( nvo
) ) != 0 )
170 * Fetch value of NVO setting
172 * @v settings Settings block
173 * @v setting Setting to fetch
174 * @v data Buffer to fill with setting data
175 * @v len Length of buffer
176 * @ret len Length of setting data, or negative error
178 * The actual length of the setting will be returned even if
179 * the buffer was too small.
181 static int nvo_fetch ( struct settings
*settings
, struct setting
*setting
,
182 void *data
, size_t len
) {
183 struct nvo_block
*nvo
=
184 container_of ( settings
, struct nvo_block
, settings
);
186 return dhcpopt_fetch ( &nvo
->dhcpopts
, setting
->tag
, data
, len
);
189 /** NVO settings operations */
190 static struct settings_operations nvo_settings_operations
= {
196 * Initialise non-volatile stored options
198 * @v nvo Non-volatile options block
199 * @v nvs Underlying non-volatile storage device
200 * @v fragments List of option-containing fragments
201 * @v refcnt Containing object reference counter, or NULL
203 void nvo_init ( struct nvo_block
*nvo
, struct nvs_device
*nvs
,
204 struct nvo_fragment
*fragments
, struct refcnt
*refcnt
) {
206 nvo
->fragments
= fragments
;
207 settings_init ( &nvo
->settings
, &nvo_settings_operations
, refcnt
,
212 * Register non-volatile stored options
214 * @v nvo Non-volatile options block
215 * @v parent Parent settings block, or NULL
216 * @ret rc Return status code
218 int register_nvo ( struct nvo_block
*nvo
, struct settings
*parent
) {
219 struct nvo_fragment
*fragment
= nvo
->fragments
;
222 /* Calculate total length of all fragments */
223 for ( fragment
= nvo
->fragments
; fragment
->len
; fragment
++ )
224 nvo
->total_len
+= fragment
->len
;
226 /* Allocate memory for options and read in from NVS */
227 nvo
->data
= malloc ( nvo
->total_len
);
229 DBGC ( nvo
, "NVO %p could not allocate %zd bytes\n",
230 nvo
, nvo
->total_len
);
234 if ( ( rc
= nvo_load ( nvo
) ) != 0 )
237 /* Verify and register options */
238 nvo_init_dhcpopts ( nvo
);
239 if ( ( rc
= register_settings ( &nvo
->settings
, parent
) ) != 0 )
242 DBGC ( nvo
, "NVO %p registered\n", nvo
);
254 * Unregister non-volatile stored options
256 * @v nvo Non-volatile options block
258 void unregister_nvo ( struct nvo_block
*nvo
) {
259 unregister_settings ( &nvo
->settings
);
262 DBGC ( nvo
, "NVO %p unregistered\n", nvo
);