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.
28 #include <gpxe/vsprintf.h>
29 #include <gpxe/settings.h>
33 * Configuration settings
37 /** Registered configuration setting types */
38 static struct config_setting_type config_setting_types[0]
39 __table_start ( struct config_setting_type, config_setting_types );
40 static struct config_setting_type config_setting_types_end[0]
41 __table_end ( struct config_setting_type, config_setting_types );
43 /** Registered configuration settings */
44 static struct config_setting config_settings[0]
45 __table_start ( struct config_setting, config_settings );
46 static struct config_setting config_settings_end[0]
47 __table_end ( struct config_setting, config_settings );
49 struct config_setting_type config_setting_type_hex __config_setting_type;
52 * Find configuration setting type
55 * @ret type Configuration setting type, or NULL
57 static struct config_setting_type *
58 find_config_setting_type ( const char *name ) {
59 struct config_setting_type *type;
61 for ( type = config_setting_types ; type < config_setting_types_end ;
63 if ( strcasecmp ( name, type->name ) == 0 )
70 * Find configuration setting
73 * @ret setting Configuration setting, or NULL
75 static struct config_setting * find_config_setting ( const char *name ) {
76 struct config_setting *setting;
78 for ( setting = config_settings ; setting < config_settings_end ;
80 if ( strcasecmp ( name, setting->name ) == 0 )
87 * Find or build configuration setting
90 * @v tmp_setting Temporary buffer for constructing a setting
91 * @ret setting Configuration setting, or NULL
93 * Find setting if it exists. If it doesn't exist, but the name is of
94 * the form "<num>:<type>" (e.g. "12:string"), then construct a
95 * setting for that tag and data type, and return it. The constructed
96 * setting will be placed in the temporary buffer.
98 static struct config_setting *
99 find_or_build_config_setting ( const char *name,
100 struct config_setting *tmp_setting ) {
101 struct config_setting *setting;
104 /* Look in the list of registered settings first */
105 setting = find_config_setting ( name );
109 /* If name is of the form "<num>:<type>", try to construct a setting */
110 setting = tmp_setting;
111 memset ( setting, 0, sizeof ( *setting ) );
112 setting->name = name;
113 for ( separator = ( char * ) name ; 1 ; separator++ ) {
114 setting->tag = ( ( setting->tag << 8 ) |
115 strtoul ( separator, &separator, 0 ) );
116 if ( *separator != '.' )
120 switch ( *separator ) {
122 setting->type = find_config_setting_type ( separator + 1 );
125 setting->type = &config_setting_type_hex;
130 if ( ! setting->type )
136 * Show value of named setting
138 * @v context Configuration context
139 * @v name Configuration setting name
140 * @v buf Buffer to contain value
141 * @v len Length of buffer
142 * @ret len Length of formatted value, or negative error
144 int show_named_setting ( struct config_context *context, const char *name,
145 char *buf, size_t len ) {
146 struct config_setting *setting;
147 struct config_setting tmp_setting;
149 setting = find_or_build_config_setting ( name, &tmp_setting );
152 return show_setting ( context, setting, buf, len );
156 * Set value of named setting
158 * @v context Configuration context
159 * @v name Configuration setting name
160 * @v value Setting value (as a string)
161 * @ret rc Return status code
163 int set_named_setting ( struct config_context *context, const char *name,
164 const char *value ) {
165 struct config_setting *setting;
166 struct config_setting tmp_setting;
168 setting = find_or_build_config_setting ( name, &tmp_setting );
171 return setting->type->set ( context, setting, value );
175 * Set value of setting
177 * @v context Configuration context
178 * @v setting Configuration setting
179 * @v value Setting value (as a string), or NULL
180 * @ret rc Return status code
182 int set_setting ( struct config_context *context,
183 struct config_setting *setting,
184 const char *value ) {
185 if ( ( ! value ) || ( ! *value ) ) {
186 /* Save putting deletion logic in each individual handler */
187 return clear_setting ( context, setting );
189 return setting->type->set ( context, setting, value );
193 * Show value of string setting
195 * @v context Configuration context
196 * @v setting Configuration setting
197 * @v buf Buffer to contain value
198 * @v len Length of buffer
199 * @ret len Length of formatted value, or negative error
201 static int show_string ( struct config_context *context,
202 struct config_setting *setting,
203 char *buf, size_t len ) {
204 struct dhcp_option *option;
206 option = find_dhcp_option ( context->options, setting->tag );
209 return dhcp_snprintf ( buf, len, option );
213 * Set value of string setting
215 * @v context Configuration context
216 * @v setting Configuration setting
217 * @v value Setting value (as a string)
218 * @ret rc Return status code
220 static int set_string ( struct config_context *context,
221 struct config_setting *setting,
222 const char *value ) {
223 struct dhcp_option *option;
225 option = set_dhcp_option ( context->options, setting->tag,
226 value, strlen ( value ) );
232 /** A string configuration setting */
233 struct config_setting_type config_setting_type_string __config_setting_type = {
235 .description = "Text string",
241 * Show value of IPv4 setting
243 * @v context Configuration context
244 * @v setting Configuration setting
245 * @v buf Buffer to contain value
246 * @v len Length of buffer
247 * @ret len Length of formatted value, or negative error
249 static int show_ipv4 ( struct config_context *context,
250 struct config_setting *setting,
251 char *buf, size_t len ) {
252 struct dhcp_option *option;
255 option = find_dhcp_option ( context->options, setting->tag );
258 dhcp_ipv4_option ( option, &ipv4 );
259 return snprintf ( buf, len, inet_ntoa ( ipv4 ) );
263 * Set value of IPV4 setting
265 * @v context Configuration context
266 * @v setting Configuration setting
267 * @v value Setting value (as a string)
268 * @ret rc Return status code
270 static int set_ipv4 ( struct config_context *context,
271 struct config_setting *setting,
272 const char *value ) {
273 struct dhcp_option *option;
276 if ( inet_aton ( value, &ipv4 ) == 0 )
278 option = set_dhcp_option ( context->options, setting->tag,
279 &ipv4, sizeof ( ipv4 ) );
285 /** An IPv4 configuration setting */
286 struct config_setting_type config_setting_type_ipv4 __config_setting_type = {
288 .description = "IPv4 address",
294 * Show value of integer setting
296 * @v context Configuration context
297 * @v setting Configuration setting
298 * @v buf Buffer to contain value
299 * @v len Length of buffer
300 * @ret len Length of formatted value, or negative error
302 static int show_int ( struct config_context *context,
303 struct config_setting *setting,
304 char *buf, size_t len ) {
305 struct dhcp_option *option;
308 option = find_dhcp_option ( context->options, setting->tag );
311 num = dhcp_num_option ( option );
312 return snprintf ( buf, len, "%ld", num );
316 * Set value of integer setting
318 * @v context Configuration context
319 * @v setting Configuration setting
320 * @v value Setting value (as a string)
321 * @v size Size of integer (in bytes)
322 * @ret rc Return status code
324 static int set_int ( struct config_context *context,
325 struct config_setting *setting,
326 const char *value, unsigned int size ) {
327 struct dhcp_option *option;
337 u.num = htonl ( strtoul ( value, &endp, 0 ) );
342 option = set_dhcp_option ( context->options, setting->tag,
343 &u.bytes[ sizeof ( u ) - size ], size );
350 * Set value of 8-bit integer setting
352 * @v context Configuration context
353 * @v setting Configuration setting
354 * @v value Setting value (as a string)
355 * @v size Size of integer (in bytes)
356 * @ret rc Return status code
358 static int set_int8 ( struct config_context *context,
359 struct config_setting *setting,
360 const char *value ) {
361 return set_int ( context, setting, value, 1 );
365 * Set value of 16-bit integer setting
367 * @v context Configuration context
368 * @v setting Configuration setting
369 * @v value Setting value (as a string)
370 * @v size Size of integer (in bytes)
371 * @ret rc Return status code
373 static int set_int16 ( struct config_context *context,
374 struct config_setting *setting,
375 const char *value ) {
376 return set_int ( context, setting, value, 2 );
380 * Set value of 32-bit integer setting
382 * @v context Configuration context
383 * @v setting Configuration setting
384 * @v value Setting value (as a string)
385 * @v size Size of integer (in bytes)
386 * @ret rc Return status code
388 static int set_int32 ( struct config_context *context,
389 struct config_setting *setting,
390 const char *value ) {
391 return set_int ( context, setting, value, 4 );
394 /** An 8-bit integer configuration setting */
395 struct config_setting_type config_setting_type_int8 __config_setting_type = {
397 .description = "8-bit integer",
402 /** A 16-bit integer configuration setting */
403 struct config_setting_type config_setting_type_int16 __config_setting_type = {
405 .description = "16-bit integer",
410 /** A 32-bit integer configuration setting */
411 struct config_setting_type config_setting_type_int32 __config_setting_type = {
413 .description = "32-bit integer",
419 * Set value of hex-string setting
421 * @v context Configuration context
422 * @v setting Configuration setting
423 * @v value Setting value (as a string)
424 * @ret rc Return status code
426 static int set_hex ( struct config_context *context,
427 struct config_setting *setting,
428 const char *value ) {
429 struct dhcp_option *option;
430 char *ptr = ( char * ) value;
431 uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
432 unsigned int len = 0;
435 bytes[len++] = strtoul ( ptr, &ptr, 16 );
438 option = set_dhcp_option ( context->options,
439 setting->tag, bytes, len );
453 * Show value of hex-string setting
455 * @v context Configuration context
456 * @v setting Configuration setting
457 * @v buf Buffer to contain value
458 * @v len Length of buffer
459 * @ret len Length of formatted value, or negative error
461 static int show_hex ( struct config_context *context,
462 struct config_setting *setting,
463 char *buf, size_t len ) {
464 struct dhcp_option *option;
468 option = find_dhcp_option ( context->options, setting->tag );
472 for ( i = 0 ; i < option->len ; i++ ) {
473 used += ssnprintf ( ( buf + used ), ( len - used ),
474 "%s%02x", ( used ? ":" : "" ),
475 option->data.bytes[i] );
480 /** A hex-string configuration setting */
481 struct config_setting_type config_setting_type_hex __config_setting_type = {
483 .description = "Hex string",
488 /** Some basic setting definitions */
489 struct config_setting basic_config_settings[] __config_setting = {
492 .description = "IP address of this machine (e.g. 192.168.0.1)",
493 .tag = DHCP_EB_YIADDR,
494 .type = &config_setting_type_ipv4,
498 .description = "Host name of this machine",
499 .tag = DHCP_HOST_NAME,
500 .type = &config_setting_type_string,
504 .description = "User name for authentication to servers",
505 .tag = DHCP_EB_USERNAME,
506 .type = &config_setting_type_string,
510 .description = "Password for authentication to servers",
511 .tag = DHCP_EB_PASSWORD,
512 .type = &config_setting_type_string,
516 .description = "NFS/iSCSI root path",
517 .tag = DHCP_ROOT_PATH,
518 .type = &config_setting_type_string,
522 .description = "Priority of these options",
523 .tag = DHCP_EB_PRIORITY,
524 .type = &config_setting_type_int8,
527 .name = "initiator-iqn",
528 .description = "iSCSI qualified name of this machine",
529 .tag = DHCP_ISCSI_INITIATOR_IQN,
530 .type = &config_setting_type_string,