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 );
51 * Obtain printable version of a settings tag number
53 * @v tag Settings tag number
54 * @ret name String representation of the tag
56 static inline char * setting_tag_name ( unsigned int tag ) {
59 if ( DHCP_IS_ENCAP_OPT ( tag ) ) {
60 snprintf ( name, sizeof ( name ), "%d.%d",
61 DHCP_ENCAPSULATOR ( tag ),
62 DHCP_ENCAPSULATED ( tag ) );
64 snprintf ( name, sizeof ( name ), "%d", tag );
69 /******************************************************************************
71 * Registered settings blocks
73 ******************************************************************************
76 // Dummy routine just for testing
77 int simple_settings_store ( struct settings *settings, unsigned int tag,
78 const void *data, size_t len ) {
79 DBGC ( settings, "Settings %p: store %s to:\n",
80 settings, setting_tag_name ( tag ) );
81 DBGC_HD ( settings, data, len );
85 // Dummy routine just for testing
86 int simple_settings_fetch ( struct settings *settings, unsigned int tag,
87 void *data, size_t len ) {
90 DBGC ( settings, "Settings %p: fetch %s\n",
91 settings, setting_tag_name ( tag ) );
92 for ( i = 0 ; i < len ; i++ )
93 *( ( ( uint8_t * ) data ) + i ) = i;
94 return ( len ? len : 8 );
97 // Dummy routine just for testing
98 static void apply_settings ( void ) {
101 /** Simple settings operations */
102 struct settings_operations simple_settings_operations = {
103 .store = simple_settings_store,
104 .fetch = simple_settings_fetch,
107 /** Root settings block */
108 struct settings settings_root = {
111 .siblings = LIST_HEAD_INIT ( settings_root.siblings ),
112 .children = LIST_HEAD_INIT ( settings_root.children ),
113 .op = &simple_settings_operations,
117 * Register settings block
119 * @v settings Settings block
120 * @v parent Parent settings block, or NULL
121 * @ret rc Return status code
123 int register_settings ( struct settings *settings, struct settings *parent ) {
125 /* NULL parent => add to settings root */
126 assert ( settings != NULL );
127 if ( parent == NULL )
128 parent = &settings_root;
130 /* Add to list of settings */
131 ref_get ( settings->refcnt );
132 ref_get ( parent->refcnt );
133 settings->parent = parent;
134 list_add_tail ( &settings->siblings, &parent->children );
135 DBGC ( settings, "Settings %p registered\n", settings );
137 /* Apply potentially-updated settings */
144 * Unregister settings block
146 * @v settings Settings block
148 void unregister_settings ( struct settings *settings ) {
150 /* Remove from list of settings */
151 ref_put ( settings->refcnt );
152 ref_put ( settings->parent->refcnt );
153 list_del ( &settings->siblings );
154 DBGC ( settings, "Settings %p unregistered\n", settings );
156 /* Apply potentially-updated settings */
161 * Find child named settings block
163 * @v parent Parent settings block
164 * @v name Name within this parent
165 * @ret settings Settings block, or NULL
167 struct settings * find_child_settings ( struct settings *parent,
169 struct settings *settings;
172 /* Look for a child whose name matches the initial component */
173 list_for_each_entry ( settings, &parent->children, siblings ) {
174 len = strlen ( settings->name );
175 if ( strncmp ( name, settings->name, len ) != 0 )
177 if ( name[len] == 0 )
179 if ( name[len] == '.' )
180 return find_child_settings ( settings,
181 ( name + len + 1 ) );
188 * Find named settings block
191 * @ret settings Settings block, or NULL
193 struct settings * find_settings ( const char *name ) {
195 /* If name is empty, use the root */
197 return &settings_root;
199 return find_child_settings ( &settings_root, name );
202 /******************************************************************************
204 * Core settings routines
206 ******************************************************************************
210 * Fetch value of setting
212 * @v settings Settings block, or NULL to search all blocks
213 * @v tag Setting tag number
214 * @v data Buffer to fill with setting data
215 * @v len Length of buffer
216 * @ret len Length of setting data, or negative error
218 * The actual length of the setting will be returned even if
219 * the buffer was too small.
221 int fetch_setting ( struct settings *settings, unsigned int tag,
222 void *data, size_t len ) {
223 struct settings *child;
226 /* NULL settings implies starting at the global settings root */
228 settings = &settings_root;
230 /* Try this block first */
231 if ( ( ret = settings->op->fetch ( settings, tag, data, len ) ) >= 0)
234 /* Recurse into each child block in turn */
235 list_for_each_entry ( child, &settings->children, siblings ) {
236 if ( ( ret = fetch_setting ( settings, tag, data, len ) ) >= 0)
244 * Fetch length of setting
246 * @v settings Settings block, or NULL to search all blocks
247 * @v tag Setting tag number
248 * @ret len Length of setting data, or negative error
250 * This function can also be used as an existence check for the
253 int fetch_setting_len ( struct settings *settings, unsigned int tag ) {
254 return fetch_setting ( settings, tag, NULL, 0 );
258 * Fetch value of string setting
260 * @v settings Settings block, or NULL to search all blocks
261 * @v tag Setting tag number
262 * @v data Buffer to fill with setting string data
263 * @v len Length of buffer
264 * @ret len Length of string setting, or negative error
266 * The resulting string is guaranteed to be correctly NUL-terminated.
267 * The returned length will be the length of the underlying setting
270 int fetch_string_setting ( struct settings *settings, unsigned int tag,
271 char *data, size_t len ) {
272 memset ( data, 0, len );
273 return fetch_setting ( settings, tag, data, ( len - 1 ) );
277 * Fetch value of IPv4 address setting
279 * @v settings Settings block, or NULL to search all blocks
280 * @v tag Setting tag number
281 * @v inp IPv4 address to fill in
282 * @ret len Length of setting, or negative error
284 int fetch_ipv4_setting ( struct settings *settings, unsigned int tag,
285 struct in_addr *inp ) {
288 len = fetch_setting ( settings, tag, inp, sizeof ( *inp ) );
291 if ( len != sizeof ( *inp ) )
297 * Fetch value of signed integer setting
299 * @v settings Settings block, or NULL to search all blocks
300 * @v tag Setting tag number
301 * @v value Integer value to fill in
302 * @ret len Length of setting, or negative error
304 int fetch_int_setting ( struct settings *settings, unsigned int tag,
308 uint8_t u8[ sizeof ( long ) ];
309 int8_t s8[ sizeof ( long ) ];
315 len = fetch_setting ( settings, tag, &buf, sizeof ( buf ) );
318 if ( len > ( int ) sizeof ( buf ) )
321 *value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
322 for ( i = 0 ; i < len ; i++ ) {
323 *value = ( ( *value << 8 ) | buf.u8[i] );
330 * Fetch value of unsigned integer setting
332 * @v settings Settings block, or NULL to search all blocks
333 * @v tag Setting tag number
334 * @v value Integer value to fill in
335 * @ret len Length of setting, or negative error
337 int fetch_uint_setting ( struct settings *settings, unsigned int tag,
338 unsigned long *value ) {
342 len = fetch_int_setting ( settings, tag, &svalue );
346 *value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) );
351 /******************************************************************************
353 * Named and typed setting routines
355 ******************************************************************************
359 * Store value of typed setting
361 * @v settings Settings block
362 * @v tag Setting tag number
363 * @v type Settings type
364 * @v value Formatted setting data, or NULL
365 * @ret rc Return status code
367 int store_typed_setting ( struct settings *settings,
368 unsigned int tag, struct setting_type *type,
369 const char *value ) {
371 /* NULL value implies deletion. Avoid imposing the burden of
372 * checking for NULL values on each typed setting's storef()
376 return delete_setting ( settings, tag );
378 return type->storef ( settings, tag, value );
385 * @ret setting Named setting, or NULL
387 static struct named_setting * find_named_setting ( const char *name ) {
388 struct named_setting *setting;
390 for ( setting = named_settings ; setting < named_settings_end ;
392 if ( strcmp ( name, setting->name ) == 0 )
402 * @ret type Setting type, or NULL
404 static struct setting_type * find_setting_type ( const char *name ) {
405 struct setting_type *type;
407 for ( type = setting_types ; type < setting_types_end ; type++ ) {
408 if ( strcmp ( name, type->name ) == 0 )
417 * @v name Name of setting
418 * @ret settings Settings block, or NULL
419 * @ret tag Setting tag number
420 * @ret type Setting type
421 * @ret rc Return status code
423 * Interprets a name of the form
424 * "[settings_name/]tag_name[:type_name]" and fills in the appropriate
427 static int parse_setting_name ( const char *name, struct settings **settings,
429 struct setting_type **type ) {
430 char tmp_name[ strlen ( name ) + 1 ];
434 struct named_setting *named_setting;
438 *settings = &settings_root;
440 *type = &setting_type_hex;
442 /* Split name into "[settings_name/]tag_name[:type_name]" */
443 memcpy ( tmp_name, name, sizeof ( tmp_name ) );
444 if ( ( tag_name = strchr ( tmp_name, '/' ) ) != NULL ) {
446 settings_name = tmp_name;
449 settings_name = NULL;
451 if ( ( type_name = strchr ( tag_name, ':' ) ) != NULL )
454 /* Identify settings block, if specified */
455 if ( settings_name ) {
456 *settings = find_settings ( settings_name );
457 if ( *settings == NULL ) {
458 DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n",
459 settings_name, name );
464 /* Identify tag number */
465 if ( ( named_setting = find_named_setting ( tag_name ) ) != NULL ) {
466 *tag = named_setting->tag;
467 *type = named_setting->type;
469 /* Unrecognised name: try to interpret as a tag number */
472 *tag = ( ( *tag << 8 ) | strtoul ( tmp, &tmp, 0 ) );
476 DBG ( "Invalid tag number \"%s\" in \"%s\"\n",
484 /* Identify setting type, if specified */
486 *type = find_setting_type ( type_name );
487 if ( *type == NULL ) {
488 DBG ( "Invalid setting type \"%s\" in \"%s\"\n",
498 * Parse and store value of named setting
500 * @v name Name of setting
501 * @v value Formatted setting data, or NULL
502 * @ret rc Return status code
504 int store_named_setting ( const char *name, const char *value ) {
505 struct settings *settings;
507 struct setting_type *type;
510 if ( ( rc = parse_setting_name ( name, &settings, &tag,
513 return store_typed_setting ( settings, tag, type, value );
517 * Fetch and format value of named setting
519 * @v name Name of setting
520 * @v buf Buffer to contain formatted value
521 * @v len Length of buffer
522 * @ret len Length of formatted value, or negative error
524 int fetch_named_setting ( const char *name, char *buf, size_t len ) {
525 struct settings *settings;
527 struct setting_type *type;
530 if ( ( rc = parse_setting_name ( name, &settings, &tag,
533 return fetch_typed_setting ( settings, tag, type, buf, len );
536 /******************************************************************************
540 ******************************************************************************
544 * Parse and store value of string setting
546 * @v settings Settings block
547 * @v tag Setting tag number
548 * @v value Formatted setting data
549 * @ret rc Return status code
551 static int storef_string ( struct settings *settings, unsigned int tag,
552 const char *value ) {
553 return store_setting ( settings, tag, value, strlen ( value ) );
557 * Fetch and format value of string setting
559 * @v settings Settings block, or NULL to search all blocks
560 * @v tag Setting tag number
561 * @v buf Buffer to contain formatted value
562 * @v len Length of buffer
563 * @ret len Length of formatted value, or negative error
565 static int fetchf_string ( struct settings *settings, unsigned int tag,
566 char *buf, size_t len ) {
567 return fetch_string_setting ( settings, tag, buf, len );
570 /** A string setting type */
571 struct setting_type setting_type_string __setting_type = {
573 .storef = storef_string,
574 .fetchf = fetchf_string,
578 * Parse and store value of IPv4 address setting
580 * @v settings Settings block
581 * @v tag Setting tag number
582 * @v value Formatted setting data
583 * @ret rc Return status code
585 static int storef_ipv4 ( struct settings *settings, unsigned int tag,
586 const char *value ) {
589 if ( inet_aton ( value, &ipv4 ) == 0 )
591 return store_setting ( settings, tag, &ipv4, sizeof ( ipv4 ) );
595 * Fetch and format value of IPv4 address setting
597 * @v settings Settings block, or NULL to search all blocks
598 * @v tag Setting tag number
599 * @v buf Buffer to contain formatted value
600 * @v len Length of buffer
601 * @ret len Length of formatted value, or negative error
603 static int fetchf_ipv4 ( struct settings *settings, unsigned int tag,
604 char *buf, size_t len ) {
608 if ( ( rc = fetch_ipv4_setting ( settings, tag, &ipv4 ) ) < 0 )
610 return snprintf ( buf, len, inet_ntoa ( ipv4 ) );
613 /** An IPv4 address setting type */
614 struct setting_type setting_type_ipv4 __setting_type = {
616 .storef = storef_ipv4,
617 .fetchf = fetchf_ipv4,
621 * Parse and store value of integer setting
623 * @v settings Settings block
624 * @v tag Setting tag number
625 * @v value Formatted setting data
626 * @v size Integer size, in bytes
627 * @ret rc Return status code
629 static int storef_int ( struct settings *settings, unsigned int tag,
630 const char *value, unsigned int size ) {
637 u.num = htonl ( strtoul ( value, &endp, 0 ) );
640 return store_setting ( settings, tag,
641 &u.bytes[ sizeof ( u ) - size ], size );
645 * Parse and store value of 8-bit integer setting
647 * @v settings Settings block
648 * @v tag Setting tag number
649 * @v value Formatted setting data
650 * @v size Integer size, in bytes
651 * @ret rc Return status code
653 static int storef_int8 ( struct settings *settings, unsigned int tag,
654 const char *value ) {
655 return storef_int ( settings, tag, value, 1 );
659 * Parse and store value of 16-bit integer setting
661 * @v settings Settings block
662 * @v tag Setting tag number
663 * @v value Formatted setting data
664 * @v size Integer size, in bytes
665 * @ret rc Return status code
667 static int storef_int16 ( struct settings *settings, unsigned int tag,
668 const char *value ) {
669 return storef_int ( settings, tag, value, 2 );
673 * Parse and store value of 32-bit integer setting
675 * @v settings Settings block
676 * @v tag Setting tag number
677 * @v value Formatted setting data
678 * @v size Integer size, in bytes
679 * @ret rc Return status code
681 static int storef_int32 ( struct settings *settings, unsigned int tag,
682 const char *value ) {
683 return storef_int ( settings, tag, value, 4 );
687 * Fetch and format value of signed integer setting
689 * @v settings Settings block, or NULL to search all blocks
690 * @v tag Setting tag number
691 * @v buf Buffer to contain formatted value
692 * @v len Length of buffer
693 * @ret len Length of formatted value, or negative error
695 static int fetchf_int ( struct settings *settings, unsigned int tag,
696 char *buf, size_t len ) {
700 if ( ( rc = fetch_int_setting ( settings, tag, &value ) ) < 0 )
702 return snprintf ( buf, len, "%ld", value );
706 * Fetch and format value of unsigned integer setting
708 * @v settings Settings block, or NULL to search all blocks
709 * @v tag Setting tag number
710 * @v buf Buffer to contain formatted value
711 * @v len Length of buffer
712 * @ret len Length of formatted value, or negative error
714 static int fetchf_uint ( struct settings *settings, unsigned int tag,
715 char *buf, size_t len ) {
719 if ( ( rc = fetch_uint_setting ( settings, tag, &value ) ) < 0 )
721 return snprintf ( buf, len, "%#lx", value );
724 /** A signed 8-bit integer setting type */
725 struct setting_type setting_type_int8 __setting_type = {
727 .storef = storef_int8,
728 .fetchf = fetchf_int,
731 /** A signed 16-bit integer setting type */
732 struct setting_type setting_type_int16 __setting_type = {
734 .storef = storef_int16,
735 .fetchf = fetchf_int,
738 /** A signed 32-bit integer setting type */
739 struct setting_type setting_type_int32 __setting_type = {
741 .storef = storef_int32,
742 .fetchf = fetchf_int,
745 /** An unsigned 8-bit integer setting type */
746 struct setting_type setting_type_uint8 __setting_type = {
748 .storef = storef_int8,
749 .fetchf = fetchf_uint,
752 /** An unsigned 16-bit integer setting type */
753 struct setting_type setting_type_uint16 __setting_type = {
755 .storef = storef_int16,
756 .fetchf = fetchf_uint,
759 /** An unsigned 32-bit integer setting type */
760 struct setting_type setting_type_uint32 __setting_type = {
762 .storef = storef_int32,
763 .fetchf = fetchf_uint,
767 * Parse and store value of hex string setting
769 * @v settings Settings block
770 * @v tag Setting tag number
771 * @v value Formatted setting data
772 * @ret rc Return status code
774 static int storef_hex ( struct settings *settings, unsigned int tag,
775 const char *value ) {
776 char *ptr = ( char * ) value;
777 uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
778 unsigned int len = 0;
781 bytes[len++] = strtoul ( ptr, &ptr, 16 );
784 return store_setting ( settings, tag, bytes, len );
795 * Fetch and format value of hex string setting
797 * @v settings Settings block, or NULL to search all blocks
798 * @v tag Setting tag number
799 * @v buf Buffer to contain formatted value
800 * @v len Length of buffer
801 * @ret len Length of formatted value, or negative error
803 static int fetchf_hex ( struct settings *settings, unsigned int tag,
804 char *buf, size_t len ) {
810 raw_len = fetch_setting_len ( settings, tag );
815 uint8_t raw[raw_len];
817 check_len = fetch_setting ( settings, tag, raw, sizeof (raw) );
818 assert ( check_len == raw_len );
821 buf[0] = 0; /* Ensure that a terminating NUL exists */
822 for ( i = 0 ; i < raw_len ; i++ ) {
823 used += ssnprintf ( ( buf + used ), ( len - used ),
824 "%s%02x", ( used ? ":" : "" ),
831 /** A hex-string setting */
832 struct setting_type setting_type_hex __setting_type = {
834 .storef = storef_hex,
835 .fetchf = fetchf_hex,
838 /******************************************************************************
842 ******************************************************************************
845 /** Some basic setting definitions */
846 struct named_setting basic_named_settings[] __named_setting = {
849 .description = "IPv4 address",
850 .tag = DHCP_EB_YIADDR,
851 .type = &setting_type_ipv4,
855 .description = "IPv4 subnet mask",
856 .tag = DHCP_SUBNET_MASK,
857 .type = &setting_type_ipv4,
861 .description = "Default gateway",
863 .type = &setting_type_ipv4,
867 .description = "DNS server",
868 .tag = DHCP_DNS_SERVERS,
869 .type = &setting_type_ipv4,
873 .description = "Host name",
874 .tag = DHCP_HOST_NAME,
875 .type = &setting_type_string,
879 .description = "Boot filename",
880 .tag = DHCP_BOOTFILE_NAME,
881 .type = &setting_type_string,
885 .description = "NFS/iSCSI root path",
886 .tag = DHCP_ROOT_PATH,
887 .type = &setting_type_string,
891 .description = "User name",
892 .tag = DHCP_EB_USERNAME,
893 .type = &setting_type_string,
897 .description = "Password",
898 .tag = DHCP_EB_PASSWORD,
899 .type = &setting_type_string,
902 .name = "initiator-iqn",
903 .description = "iSCSI initiator name",
904 .tag = DHCP_ISCSI_INITIATOR_IQN,
905 .type = &setting_type_string,
909 .description = "Priority of these settings",
910 .tag = DHCP_EB_PRIORITY,
911 .type = &setting_type_int8,