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.
22 #include <gpxe/dhcp.h>
28 * Non-volatile stored options
32 /* FIXME: "Temporary hack" */
33 struct nvo_block
*ugly_nvo_hack
= NULL
;
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
->options
->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
->options
->data
;
60 struct nvo_fragment
*fragment
;
63 /* Read data a fragment at a time */
64 for ( fragment
= nvo
->fragments
; fragment
->len
; fragment
++ ) {
65 if ( ( rc
= nvs_read ( nvo
->nvs
, fragment
->address
,
66 data
, fragment
->len
) ) != 0 ) {
67 DBG ( "NVO %p could not read %zd bytes at %#04x\n",
68 nvo
, fragment
->len
, fragment
->address
);
71 data
+= fragment
->len
;
74 DBG ( "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 int nvo_save ( struct nvo_block
*nvo
) {
85 void *data
= nvo
->options
->data
;
86 uint8_t *checksum
= ( data
+ nvo
->total_len
- 1 );
87 struct nvo_fragment
*fragment
;
90 /* Recalculate checksum */
91 *checksum
-= nvo_checksum ( nvo
);
93 /* Write data a fragment at a time */
94 for ( fragment
= nvo
->fragments
; fragment
->len
; fragment
++ ) {
95 if ( ( rc
= nvs_write ( nvo
->nvs
, fragment
->address
,
96 data
, fragment
->len
) ) != 0 ) {
97 DBG ( "NVO %p could not write %zd bytes at %#04x\n",
98 nvo
, fragment
->len
, fragment
->address
);
101 data
+= fragment
->len
;
104 DBG ( "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_dhcp ( struct nvo_block
*nvo
) {
118 struct dhcp_option_block
*options
= nvo
->options
;
119 struct dhcp_option
*option
;
121 /* Steal one byte for the checksum */
122 options
->max_len
= ( nvo
->total_len
- 1 );
124 /* Verify checksum over whole block */
125 if ( nvo_checksum ( nvo
) != 0 ) {
126 DBG ( "NVO %p has bad checksum %02x; assuming empty\n",
127 nvo
, nvo_checksum ( nvo
) );
131 /* Check that we don't just have a block full of zeroes */
132 option
= options
->data
;
133 if ( option
->tag
== DHCP_PAD
) {
134 DBG ( "NVO %p has bad start; assuming empty\n", nvo
);
138 /* Search for the DHCP_END tag */
139 options
->len
= options
->max_len
;
140 option
= find_dhcp_option ( options
, DHCP_END
);
142 DBG ( "NVO %p has no end tag; assuming empty\n", nvo
);
146 /* Set correct length of DHCP options */
147 options
->len
= ( ( void * ) option
- options
->data
+ 1 );
148 DBG ( "NVO %p contains %zd bytes of options (maximum %zd)\n",
149 nvo
, options
->len
, options
->max_len
);
153 /* No options found; initialise an empty options block */
154 option
= options
->data
;
155 option
->tag
= DHCP_END
;
161 * Register non-volatile stored options
163 * @v nvo Non-volatile options block
164 * @ret rc Return status code
166 int nvo_register ( struct nvo_block
*nvo
) {
167 struct nvo_fragment
*fragment
= nvo
->fragments
;
170 /* Calculate total length of all fragments */
172 for ( fragment
= nvo
->fragments
; fragment
->len
; fragment
++ ) {
173 nvo
->total_len
+= fragment
->len
;
176 /* Allocate memory for options and read in from NVS */
177 nvo
->options
= alloc_dhcp_options ( nvo
->total_len
);
178 if ( ! nvo
->options
) {
179 DBG ( "NVO %p could not allocate %zd bytes\n",
180 nvo
, nvo
->total_len
);
184 if ( ( rc
= nvo_load ( nvo
) ) != 0 )
187 /* Verify and register options */
188 nvo_init_dhcp ( nvo
);
189 register_dhcp_options ( nvo
->options
);
193 DBG ( "NVO %p registered\n", nvo
);
197 dhcpopt_put ( nvo
->options
);
203 * Unregister non-volatile stored options
205 * @v nvo Non-volatile options block
207 void nvo_unregister ( struct nvo_block
*nvo
) {
209 if ( nvo
->options
) {
210 unregister_dhcp_options ( nvo
->options
);
211 dhcpopt_put ( nvo
->options
);
215 DBG ( "NVO %p unregistered\n", nvo
);
217 ugly_nvo_hack
= NULL
;