|
@@ -28,79 +28,146 @@
|
28
|
28
|
*
|
29
|
29
|
*/
|
30
|
30
|
|
31
|
|
-static size_t nvo_options_len ( struct nvs_options *nvo ) {
|
|
31
|
+/**
|
|
32
|
+ * Calculate total length of non-volatile stored options
|
|
33
|
+ *
|
|
34
|
+ * @v nvo Non-volatile options block
|
|
35
|
+ * @ret total_len Total length of all fragments
|
|
36
|
+ */
|
|
37
|
+static size_t nvo_total_len ( struct nvo_block *nvo ) {
|
|
38
|
+ struct nvo_fragment *fragment = nvo->fragments;
|
|
39
|
+ size_t total_len = 0;
|
|
40
|
+
|
|
41
|
+ for ( ; fragment->len ; fragment++ ) {
|
|
42
|
+ total_len += fragment->len;
|
|
43
|
+ }
|
|
44
|
+
|
|
45
|
+ return total_len;
|
|
46
|
+}
|
|
47
|
+
|
|
48
|
+/**
|
|
49
|
+ * Read non-volatile stored options from non-volatile storage device
|
|
50
|
+ *
|
|
51
|
+ * @v nvo Non-volatile options block
|
|
52
|
+ * @ret rc Return status code
|
|
53
|
+ */
|
|
54
|
+static int nvo_read ( struct nvo_block *nvo ) {
|
|
55
|
+ struct nvo_fragment *fragment = nvo->fragments;
|
|
56
|
+ void *data = nvo->options->data;
|
|
57
|
+ int rc;
|
|
58
|
+
|
|
59
|
+ for ( ; fragment->len ; fragment++ ) {
|
|
60
|
+ if ( ( rc = nvs_read ( nvo->nvs, fragment->address,
|
|
61
|
+ data, fragment->len ) ) != 0 ) {
|
|
62
|
+ DBG ( "NVO %p could not read %zd bytes at %#04x\n",
|
|
63
|
+ nvo, fragment->len, fragment->address );
|
|
64
|
+ return rc;
|
|
65
|
+ }
|
|
66
|
+ data += fragment->len;
|
|
67
|
+ }
|
|
68
|
+
|
|
69
|
+ return 0;
|
|
70
|
+}
|
|
71
|
+
|
|
72
|
+/**
|
|
73
|
+ * Parse stored options
|
|
74
|
+ *
|
|
75
|
+ * @v nvo Non-volatile options block
|
|
76
|
+ * @v total_len Total length of options data
|
|
77
|
+ *
|
|
78
|
+ * Verifies that the options data is valid, and configures the DHCP
|
|
79
|
+ * options block. If the data is not valid, it is replaced with an
|
|
80
|
+ * empty options block.
|
|
81
|
+ */
|
|
82
|
+static void nvo_init_dhcp ( struct nvo_block *nvo, size_t total_len ) {
|
|
83
|
+ struct dhcp_option_block *options = nvo->options;
|
32
|
84
|
struct dhcp_option *option;
|
33
|
85
|
uint8_t sum;
|
34
|
86
|
unsigned int i;
|
35
|
|
- size_t len;
|
36
|
87
|
|
37
|
|
- for ( sum = 0, i = 0 ; i < nvo->nvs->size ; i++ ) {
|
38
|
|
- sum += * ( ( uint8_t * ) ( nvo->options->data + i ) );
|
|
88
|
+ /* Steal one byte for the checksum */
|
|
89
|
+ options->max_len = ( total_len - 1 );
|
|
90
|
+
|
|
91
|
+ /* Verify checksum over whole block */
|
|
92
|
+ for ( sum = 0, i = 0 ; i < total_len ; i++ ) {
|
|
93
|
+ sum += * ( ( uint8_t * ) ( options->data + i ) );
|
39
|
94
|
}
|
40
|
95
|
if ( sum != 0 ) {
|
41
|
96
|
DBG ( "NVO %p has bad checksum %02x; assuming empty\n",
|
42
|
97
|
nvo, sum );
|
43
|
|
- return 0;
|
|
98
|
+ goto empty;
|
44
|
99
|
}
|
45
|
100
|
|
46
|
|
- option = nvo->options->data;
|
|
101
|
+ /* Check that we don't just have a block full of zeroes */
|
|
102
|
+ option = options->data;
|
47
|
103
|
if ( option->tag == DHCP_PAD ) {
|
48
|
104
|
DBG ( "NVO %p has bad start; assuming empty\n", nvo );
|
49
|
|
- return 0;
|
|
105
|
+ goto empty;
|
50
|
106
|
}
|
51
|
107
|
|
52
|
|
- option = find_dhcp_option ( nvo->options, DHCP_END );
|
|
108
|
+ /* Search for the DHCP_END tag */
|
|
109
|
+ options->len = options->max_len;
|
|
110
|
+ option = find_dhcp_option ( options, DHCP_END );
|
53
|
111
|
if ( ! option ) {
|
54
|
112
|
DBG ( "NVO %p has no end tag; assuming empty\n", nvo );
|
55
|
|
- return 0;
|
|
113
|
+ goto empty;
|
56
|
114
|
}
|
57
|
115
|
|
58
|
|
- len = ( ( void * ) option - nvo->options->data + 1 );
|
|
116
|
+ /* Set correct length of DHCP options */
|
|
117
|
+ options->len = ( ( void * ) option - options->data + 1 );
|
59
|
118
|
DBG ( "NVO %p contains %zd bytes of options (maximum %zd)\n",
|
60
|
|
- nvo, len, nvo->nvs->size );
|
|
119
|
+ nvo, options->len, options->max_len );
|
|
120
|
+ return;
|
61
|
121
|
|
62
|
|
- return len;
|
|
122
|
+ empty:
|
|
123
|
+ /* No options found; initialise an empty options block */
|
|
124
|
+ option = options->data;
|
|
125
|
+ option->tag = DHCP_END;
|
|
126
|
+ options->len = 1;
|
|
127
|
+ return;
|
63
|
128
|
}
|
64
|
129
|
|
65
|
|
-int nvo_register ( struct nvs_options *nvo ) {
|
66
|
|
- struct dhcp_option *option;
|
|
130
|
+/**
|
|
131
|
+ * Register non-volatile stored options
|
|
132
|
+ *
|
|
133
|
+ * @v nvo Non-volatile options block
|
|
134
|
+ * @ret rc Return status code
|
|
135
|
+ */
|
|
136
|
+int nvo_register ( struct nvo_block *nvo ) {
|
|
137
|
+ size_t total_len;
|
67
|
138
|
int rc;
|
68
|
139
|
|
69
|
|
- nvo->options = alloc_dhcp_options ( nvo->nvs->size );
|
|
140
|
+ /* Allocate memory for options and read in from NVS */
|
|
141
|
+ total_len = nvo_total_len ( nvo );
|
|
142
|
+ nvo->options = alloc_dhcp_options ( total_len );
|
70
|
143
|
if ( ! nvo->options ) {
|
71
|
144
|
DBG ( "NVO %p could not allocate %zd bytes\n",
|
72
|
|
- nvo, nvo->nvs->size );
|
|
145
|
+ nvo, total_len );
|
73
|
146
|
rc = -ENOMEM;
|
74
|
147
|
goto err;
|
75
|
148
|
}
|
76
|
149
|
|
77
|
|
- if ( ( rc = nvo->nvs->read ( nvo->nvs, 0, nvo->options->data,
|
78
|
|
- nvo->nvs->size ) ) != 0 ) {
|
79
|
|
- DBG ( "NVO %p could not read [0,%zd)\n",
|
80
|
|
- nvo, nvo->nvs->size );
|
|
150
|
+ if ( ( rc = nvo_read ( nvo ) ) != 0 )
|
81
|
151
|
goto err;
|
82
|
|
- }
|
83
|
|
-
|
84
|
|
- nvo->options->len = nvo->options->max_len;
|
85
|
|
- nvo->options->len = nvo_options_len ( nvo );
|
86
|
|
- if ( ! nvo->options->len ) {
|
87
|
|
- option = nvo->options->data;
|
88
|
|
- option->tag = DHCP_END;
|
89
|
|
- nvo->options->len = 1;
|
90
|
|
- }
|
91
|
152
|
|
|
153
|
+ /* Verify and register options */
|
|
154
|
+ nvo_init_dhcp ( nvo, total_len );
|
92
|
155
|
register_dhcp_options ( nvo->options );
|
93
|
156
|
|
94
|
157
|
return 0;
|
95
|
158
|
|
96
|
159
|
err:
|
97
|
|
-
|
98
|
160
|
free_dhcp_options ( nvo->options );
|
99
|
161
|
nvo->options = NULL;
|
100
|
162
|
return rc;
|
101
|
163
|
}
|
102
|
164
|
|
103
|
|
-void nvo_unregister ( struct nvs_options *nvo ) {
|
|
165
|
+/**
|
|
166
|
+ * Unregister non-volatile stored options
|
|
167
|
+ *
|
|
168
|
+ * @v nvo Non-volatile options block
|
|
169
|
+ */
|
|
170
|
+void nvo_unregister ( struct nvo_block *nvo ) {
|
104
|
171
|
if ( nvo->options ) {
|
105
|
172
|
unregister_dhcp_options ( nvo->options );
|
106
|
173
|
free_dhcp_options ( nvo->options );
|