2 * Copyright (C) 2008 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/dhcp.h>
30 #include <gpxe/settings.h>
34 * Configuration settings
38 /** Registered setting types */
39 static struct setting_type setting_types[0]
40 __table_start ( struct setting_type, setting_types );
41 static struct setting_type setting_types_end[0]
42 __table_end ( struct setting_type, setting_types );
44 /** Registered named settings */
45 static struct named_setting named_settings[0]
46 __table_start ( struct named_setting, named_settings );
47 static struct named_setting named_settings_end[0]
48 __table_end ( struct named_setting, named_settings );
50 struct setting_type setting_type_hex __setting_type;
53 * Obtain printable version of a settings tag number
55 * @v tag Settings tag number
56 * @ret name String representation of the tag
58 static inline char * setting_tag_name ( unsigned int tag ) {
61 if ( DHCP_IS_ENCAP_OPT ( tag ) ) {
62 snprintf ( name, sizeof ( name ), "%d.%d",
63 DHCP_ENCAPSULATOR ( tag ),
64 DHCP_ENCAPSULATED ( tag ) );
66 snprintf ( name, sizeof ( name ), "%d", tag );
71 /******************************************************************************
73 * Registered settings blocks
75 ******************************************************************************
78 /** List of all registered settings */
79 static struct list_head all_settings = {
80 &interactive_settings.list, &interactive_settings.list
83 // Dummy routine just for testing
84 static int dummy_set ( struct settings *settings, unsigned int tag,
85 const void *data, size_t len ) {
86 DBGC ( settings, "Settings %p: set %s to:\n",
87 settings, setting_tag_name ( tag ) );
88 DBGC_HD ( settings, data, len );
92 // Dummy routine just for testing
93 static int dummy_get ( struct settings *settings, unsigned int tag,
94 void *data, size_t len ) {
97 DBGC ( settings, "Settings %p: get %s\n",
98 settings, setting_tag_name ( tag ) );
99 for ( i = 0 ; i < len ; i++ )
100 *( ( ( uint8_t * ) data ) + i ) = i;
101 return ( len ? len : 8 );
104 struct settings_operations dummy_settings_operations = {
109 /** Interactively-edited settings */
110 struct settings interactive_settings = {
113 .list = { &all_settings, &all_settings },
114 .op = &dummy_settings_operations,
118 * Find named settings block
121 * @ret settings Settings block, or NULL
123 struct settings * find_settings ( const char *name ) {
124 struct settings *settings;
126 list_for_each_entry ( settings, &all_settings, list ) {
127 if ( strcasecmp ( name, settings->name ) == 0 )
133 /******************************************************************************
135 * Core settings routines
137 ******************************************************************************
141 * Get value of setting
143 * @v settings Settings block, or NULL to search all blocks
144 * @v tag Setting tag number
145 * @v data Buffer to fill with setting data
146 * @v len Length of buffer
147 * @ret len Length of setting data, or negative error
149 * The actual length of the setting will be returned even if
150 * the buffer was too small.
152 int get_setting ( struct settings *settings, unsigned int tag,
153 void *data, size_t len ) {
157 return settings->op->get ( settings, tag, data, len );
159 list_for_each_entry ( settings, &all_settings, list ) {
160 if ( ( ret = settings->op->get ( settings, tag,
169 * Get length of setting
171 * @v settings Settings block, or NULL to search all blocks
172 * @v tag Setting tag number
173 * @ret len Length of setting data, or negative error
175 * This function can also be used as an existence check for the
178 int get_setting_len ( struct settings *settings, unsigned int tag ) {
179 return get_setting ( settings, tag, NULL, 0 );
183 * Get value of string setting
185 * @v settings Settings block, or NULL to search all blocks
186 * @v tag Setting tag number
187 * @v data Buffer to fill with setting string data
188 * @v len Length of buffer
189 * @ret len Length of string setting, or negative error
191 * The resulting string is guaranteed to be correctly NUL-terminated.
192 * The returned length will be the length of the underlying setting
195 int get_string_setting ( struct settings *settings, unsigned int tag,
196 char *data, size_t len ) {
197 memset ( data, 0, len );
198 return get_setting ( settings, tag, data, ( len - 1 ) );
202 * Get value of IPv4 address setting
204 * @v settings Settings block, or NULL to search all blocks
205 * @v tag Setting tag number
206 * @v inp IPv4 address to fill in
207 * @ret len Length of setting, or negative error
209 int get_ipv4_setting ( struct settings *settings, unsigned int tag,
210 struct in_addr *inp ) {
213 len = get_setting ( settings, tag, inp, sizeof ( *inp ) );
216 if ( len != sizeof ( *inp ) )
222 * Get value of signed integer setting
224 * @v settings Settings block, or NULL to search all blocks
225 * @v tag Setting tag number
226 * @v value Integer value to fill in
227 * @ret len Length of setting, or negative error
229 int get_int_setting ( struct settings *settings, unsigned int tag,
233 uint8_t u8[ sizeof ( long ) ];
234 int8_t s8[ sizeof ( long ) ];
240 len = get_setting ( settings, tag, &buf, sizeof ( buf ) );
243 if ( len > ( int ) sizeof ( buf ) )
246 *value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
247 for ( i = 0 ; i < len ; i++ ) {
248 *value = ( ( *value << 8 ) | buf.u8[i] );
255 * Get value of unsigned integer setting
257 * @v settings Settings block, or NULL to search all blocks
258 * @v tag Setting tag number
259 * @v value Integer value to fill in
260 * @ret len Length of setting, or negative error
262 int get_uint_setting ( struct settings *settings, unsigned int tag,
263 unsigned long *value ) {
267 len = get_int_setting ( settings, tag, &svalue );
271 *value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) );
276 /******************************************************************************
278 * Named and typed setting routines
280 ******************************************************************************
284 * Set value of typed setting
286 * @v settings Settings block
287 * @v tag Setting tag number
288 * @v type Settings type
289 * @v value Formatted setting data, or NULL
290 * @ret rc Return status code
292 int set_typed_setting ( struct settings *settings,
293 unsigned int tag, struct setting_type *type,
294 const char *value ) {
296 /* NULL value implies deletion. Avoid imposing the burden of
297 * checking for NULL values on each typed setting's setf()
301 return delete_setting ( settings, tag );
303 return type->setf ( settings, tag, value );
310 * @ret setting Named setting, or NULL
312 static struct named_setting * find_named_setting ( const char *name ) {
313 struct named_setting *setting;
315 for ( setting = named_settings ; setting < named_settings_end ;
317 if ( strcasecmp ( name, setting->name ) == 0 )
327 * @ret type Setting type, or NULL
329 static struct setting_type * find_setting_type ( const char *name ) {
330 struct setting_type *type;
332 for ( type = setting_types ; type < setting_types_end ; type++ ) {
333 if ( strcasecmp ( name, type->name ) == 0 )
342 * @v name Name of setting
343 * @ret settings Settings block, or NULL
344 * @ret tag Setting tag number
345 * @ret type Setting type
346 * @ret rc Return status code
348 * Interprets a name of the form
349 * "[settings_name/]tag_name[:type_name]" and fills in the appropriate
352 static int parse_setting_name ( const char *name, struct settings **settings,
354 struct setting_type **type ) {
355 char tmp_name[ strlen ( name ) + 1 ];
359 struct named_setting *named_setting;
365 *type = &setting_type_hex;
367 /* Split name into "[settings_name/]tag_name[:type_name]" */
368 memcpy ( tmp_name, name, sizeof ( tmp_name ) );
369 if ( ( tag_name = strchr ( tmp_name, '/' ) ) != NULL ) {
371 settings_name = tmp_name;
374 settings_name = NULL;
376 if ( ( type_name = strchr ( tag_name, ':' ) ) != NULL )
379 /* Identify settings block, if specified */
380 if ( settings_name ) {
381 *settings = find_settings ( settings_name );
382 if ( *settings == NULL ) {
383 DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n",
384 settings_name, name );
389 /* Identify tag number */
390 if ( ( named_setting = find_named_setting ( tag_name ) ) != NULL ) {
391 *tag = named_setting->tag;
392 *type = named_setting->type;
394 /* Unrecognised name: try to interpret as a tag number */
397 *tag = ( ( *tag << 8 ) | strtoul ( tmp, &tmp, 0 ) );
401 DBG ( "Invalid tag number \"%s\" in \"%s\"\n",
409 /* Identify setting type, if specified */
411 *type = find_setting_type ( type_name );
412 if ( *type == NULL ) {
413 DBG ( "Invalid setting type \"%s\" in \"%s\"\n",
423 * Parse and set value of named setting
425 * @v name Name of setting
426 * @v value Formatted setting data, or NULL
427 * @ret rc Return status code
429 int set_named_setting ( const char *name, const char *value ) {
430 struct settings *settings;
432 struct setting_type *type;
435 if ( ( rc = parse_setting_name ( name, &settings, &tag,
438 if ( settings == NULL )
440 return set_typed_setting ( settings, tag, type, value );
444 * Get and format value of named setting
446 * @v name Name of setting
447 * @v buf Buffer to contain formatted value
448 * @v len Length of buffer
449 * @ret len Length of formatted value, or negative error
451 int get_named_setting ( const char *name, char *buf, size_t len ) {
452 struct settings *settings;
454 struct setting_type *type;
457 if ( ( rc = parse_setting_name ( name, &settings, &tag,
460 return get_typed_setting ( settings, tag, type, buf, len );
463 /******************************************************************************
467 ******************************************************************************
471 * Parse and set value of string setting
473 * @v settings Settings block
474 * @v tag Setting tag number
475 * @v value Formatted setting data
476 * @ret rc Return status code
478 static int setf_string ( struct settings *settings, unsigned int tag,
479 const char *value ) {
480 return set_setting ( settings, tag, value, strlen ( value ) );
484 * Get and format value of string setting
486 * @v settings Settings block, or NULL to search all blocks
487 * @v tag Setting tag number
488 * @v buf Buffer to contain formatted value
489 * @v len Length of buffer
490 * @ret len Length of formatted value, or negative error
492 static int getf_string ( struct settings *settings, unsigned int tag,
493 char *buf, size_t len ) {
494 return get_string_setting ( settings, tag, buf, len );
497 /** A string setting type */
498 struct setting_type setting_type_string __setting_type = {
505 * Parse and set value of IPv4 address setting
507 * @v settings Settings block
508 * @v tag Setting tag number
509 * @v value Formatted setting data
510 * @ret rc Return status code
512 static int setf_ipv4 ( struct settings *settings, unsigned int tag,
513 const char *value ) {
516 if ( inet_aton ( value, &ipv4 ) == 0 )
518 return set_setting ( settings, tag, &ipv4, sizeof ( ipv4 ) );
522 * Get and format value of IPv4 address setting
524 * @v settings Settings block, or NULL to search all blocks
525 * @v tag Setting tag number
526 * @v buf Buffer to contain formatted value
527 * @v len Length of buffer
528 * @ret len Length of formatted value, or negative error
530 static int getf_ipv4 ( struct settings *settings, unsigned int tag,
531 char *buf, size_t len ) {
535 if ( ( rc = get_ipv4_setting ( settings, tag, &ipv4 ) ) < 0 )
537 return snprintf ( buf, len, inet_ntoa ( ipv4 ) );
540 /** An IPv4 address setting type */
541 struct setting_type setting_type_ipv4 __setting_type = {
548 * Parse and set value of integer setting
550 * @v settings Settings block
551 * @v tag Setting tag number
552 * @v value Formatted setting data
553 * @v size Integer size, in bytes
554 * @ret rc Return status code
556 static int setf_int ( struct settings *settings, unsigned int tag,
557 const char *value, unsigned int size ) {
564 u.num = htonl ( strtoul ( value, &endp, 0 ) );
567 return set_setting ( settings, tag,
568 &u.bytes[ sizeof ( u ) - size ], size );
572 * Parse and set value of 8-bit integer setting
574 * @v settings Settings block
575 * @v tag Setting tag number
576 * @v value Formatted setting data
577 * @v size Integer size, in bytes
578 * @ret rc Return status code
580 static int setf_int8 ( struct settings *settings, unsigned int tag,
581 const char *value ) {
582 return setf_int ( settings, tag, value, 1 );
586 * Parse and set value of 16-bit integer setting
588 * @v settings Settings block
589 * @v tag Setting tag number
590 * @v value Formatted setting data
591 * @v size Integer size, in bytes
592 * @ret rc Return status code
594 static int setf_int16 ( struct settings *settings, unsigned int tag,
595 const char *value ) {
596 return setf_int ( settings, tag, value, 2 );
600 * Parse and set value of 32-bit integer setting
602 * @v settings Settings block
603 * @v tag Setting tag number
604 * @v value Formatted setting data
605 * @v size Integer size, in bytes
606 * @ret rc Return status code
608 static int setf_int32 ( struct settings *settings, unsigned int tag,
609 const char *value ) {
610 return setf_int ( settings, tag, value, 4 );
614 * Get and format value of signed integer setting
616 * @v settings Settings block, or NULL to search all blocks
617 * @v tag Setting tag number
618 * @v buf Buffer to contain formatted value
619 * @v len Length of buffer
620 * @ret len Length of formatted value, or negative error
622 static int getf_int ( struct settings *settings, unsigned int tag,
623 char *buf, size_t len ) {
627 if ( ( rc = get_int_setting ( settings, tag, &value ) ) < 0 )
629 return snprintf ( buf, len, "%ld", value );
633 * Get and format value of unsigned integer setting
635 * @v settings Settings block, or NULL to search all blocks
636 * @v tag Setting tag number
637 * @v buf Buffer to contain formatted value
638 * @v len Length of buffer
639 * @ret len Length of formatted value, or negative error
641 static int getf_uint ( struct settings *settings, unsigned int tag,
642 char *buf, size_t len ) {
646 if ( ( rc = get_uint_setting ( settings, tag, &value ) ) < 0 )
648 return snprintf ( buf, len, "%#lx", value );
651 /** A signed 8-bit integer setting type */
652 struct setting_type setting_type_int8 __setting_type = {
658 /** A signed 16-bit integer setting type */
659 struct setting_type setting_type_int16 __setting_type = {
665 /** A signed 32-bit integer setting type */
666 struct setting_type setting_type_int32 __setting_type = {
672 /** An unsigned 8-bit integer setting type */
673 struct setting_type setting_type_uint8 __setting_type = {
679 /** An unsigned 16-bit integer setting type */
680 struct setting_type setting_type_uint16 __setting_type = {
686 /** An unsigned 32-bit integer setting type */
687 struct setting_type setting_type_uint32 __setting_type = {
694 * Parse and set value of hex string setting
696 * @v settings Settings block
697 * @v tag Setting tag number
698 * @v value Formatted setting data
699 * @ret rc Return status code
701 static int setf_hex ( struct settings *settings, unsigned int tag,
702 const char *value ) {
703 char *ptr = ( char * ) value;
704 uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
705 unsigned int len = 0;
708 bytes[len++] = strtoul ( ptr, &ptr, 16 );
711 return set_setting ( settings, tag, bytes, len );
722 * Get and format value of hex string setting
724 * @v settings Settings block, or NULL to search all blocks
725 * @v tag Setting tag number
726 * @v buf Buffer to contain formatted value
727 * @v len Length of buffer
728 * @ret len Length of formatted value, or negative error
730 static int getf_hex ( struct settings *settings, unsigned int tag,
731 char *buf, size_t len ) {
737 raw_len = get_setting_len ( settings, tag );
742 uint8_t raw[raw_len];
744 check_len = get_setting ( settings, tag, raw, sizeof ( raw ) );
745 assert ( check_len == raw_len );
748 buf[0] = 0; /* Ensure that a terminating NUL exists */
749 for ( i = 0 ; i < raw_len ; i++ ) {
750 used += ssnprintf ( ( buf + used ), ( len - used ),
751 "%s%02x", ( used ? ":" : "" ),
758 /** A hex-string setting */
759 struct setting_type setting_type_hex __setting_type = {
765 /******************************************************************************
769 ******************************************************************************
772 /** Some basic setting definitions */
773 struct named_setting basic_named_settings[] __named_setting = {
776 .description = "IPv4 address of this interface",
777 .tag = DHCP_EB_YIADDR,
778 .type = &setting_type_ipv4,
781 .name = "subnet-mask",
782 .description = "IPv4 subnet mask",
783 .tag = DHCP_SUBNET_MASK,
784 .type = &setting_type_ipv4,
788 .description = "Default gateway",
790 .type = &setting_type_ipv4,
793 .name = "domain-name-servers",
794 .description = "DNS server",
795 .tag = DHCP_DNS_SERVERS,
796 .type = &setting_type_ipv4,
800 .description = "Host name of this machine",
801 .tag = DHCP_HOST_NAME,
802 .type = &setting_type_string,
806 .description = "Boot filename",
807 .tag = DHCP_BOOTFILE_NAME,
808 .type = &setting_type_string,
812 .description = "NFS/iSCSI root path",
813 .tag = DHCP_ROOT_PATH,
814 .type = &setting_type_string,
818 .description = "User name for authentication",
819 .tag = DHCP_EB_USERNAME,
820 .type = &setting_type_string,
824 .description = "Password for authentication",
825 .tag = DHCP_EB_PASSWORD,
826 .type = &setting_type_string,
829 .name = "initiator-iqn",
830 .description = "iSCSI initiator name",
831 .tag = DHCP_ISCSI_INITIATOR_IQN,
832 .type = &setting_type_string,
836 .description = "Priority of these options",
837 .tag = DHCP_EB_PRIORITY,
838 .type = &setting_type_int8,