7dd697ed9e9822118c4d7174f29e322f36a33110
[people/dverkamp/gpxe.git] / src / core / settings.c
1 /*
2  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <strings.h>
24 #include <byteswap.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <gpxe/in.h>
28 #include <gpxe/vsprintf.h>
29 #include <gpxe/dhcp.h>
30 #include <gpxe/settings.h>
31
32 /** @file
33  *
34  * Configuration settings
35  *
36  */
37
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 );
43
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 );
49
50 /** Registered settings applicators */
51 static struct settings_applicator settings_applicators[0]
52         __table_start ( struct settings_applicator, settings_applicators );
53 static struct settings_applicator settings_applicators_end[0]
54         __table_end ( struct settings_applicator, settings_applicators );
55
56 /**
57  * Obtain printable version of a settings tag number
58  *
59  * @v tag               Settings tag number
60  * @ret name            String representation of the tag
61  */
62 static inline char * setting_tag_name ( unsigned int tag ) {
63         static char name[8];
64
65         if ( DHCP_IS_ENCAP_OPT ( tag ) ) {
66                 snprintf ( name, sizeof ( name ), "%d.%d",
67                            DHCP_ENCAPSULATOR ( tag ),
68                            DHCP_ENCAPSULATED ( tag ) );
69         } else {
70                 snprintf ( name, sizeof ( name ), "%d", tag );
71         }
72         return name;
73 }
74
75 /******************************************************************************
76  *
77  * Registered settings blocks
78  *
79  ******************************************************************************
80  */
81
82 // Dummy routine just for testing
83 int simple_settings_store ( struct settings *settings, unsigned int tag,
84                             const void *data, size_t len ) {
85         DBGC ( settings, "Settings %p: store %s to:\n",
86                settings, setting_tag_name ( tag ) );
87         DBGC_HD ( settings, data, len );
88         return 0;
89 }
90
91 // Dummy routine just for testing
92 int simple_settings_fetch ( struct settings *settings, unsigned int tag,
93                             void *data, size_t len ) {
94         ( void ) settings;
95         ( void ) tag;
96         ( void ) data;
97         ( void ) len;
98         return -ENOENT;
99 }
100
101 /** Simple settings operations */
102 struct settings_operations simple_settings_operations = {
103         .store = simple_settings_store,
104         .fetch = simple_settings_fetch,
105 };
106
107 /** Root settings block */
108 struct settings settings_root = {
109         .refcnt = NULL,
110         .name = "",
111         .siblings = LIST_HEAD_INIT ( settings_root.siblings ),
112         .children = LIST_HEAD_INIT ( settings_root.children ),
113         .op = &simple_settings_operations,
114 };
115
116 /**
117  * Apply all settings
118  *
119  * @ret rc              Return status code
120  */
121 static int apply_settings ( void ) {
122         struct settings_applicator *applicator;
123         int rc;
124
125         /* Call all settings applicators */
126         for ( applicator = settings_applicators ;
127               applicator < settings_applicators_end ; applicator++ ) {
128                 if ( ( rc = applicator->apply() ) != 0 ) {
129                         DBG ( "Could not apply settings using applicator "
130                               "%p: %s\n", applicator, strerror ( rc ) );
131                         return rc;
132                 }
133         }
134
135         return 0;
136 }
137
138 /**
139  * Reprioritise settings
140  *
141  * @v settings          Settings block
142  *
143  * Reorders the settings block amongst its siblings according to its
144  * priority.
145  */
146 static void reprioritise_settings ( struct settings *settings ) {
147         struct settings *parent = settings->parent;
148         long priority;
149         struct settings *tmp;
150         long tmp_priority;
151
152         /* Stop when we reach the top of the tree */
153         if ( ! parent )
154                 return;
155
156         /* Read priority, if present */
157         priority = fetch_intz_setting ( settings, DHCP_EB_PRIORITY );
158
159         /* Remove from siblings list */
160         list_del ( &settings->siblings );
161
162         /* Reinsert after any existing blocks which have a higher priority */
163         list_for_each_entry ( tmp, &parent->children, siblings ) {
164                 tmp_priority = fetch_intz_setting ( tmp, DHCP_EB_PRIORITY );
165                 if ( priority > tmp_priority )
166                         break;
167         }
168         list_add_tail ( &settings->siblings, &tmp->siblings );
169
170         /* Recurse up the tree */
171         reprioritise_settings ( parent );
172 }
173
174 /**
175  * Register settings block
176  *
177  * @v settings          Settings block
178  * @v parent            Parent settings block, or NULL
179  * @ret rc              Return status code
180  */
181 int register_settings ( struct settings *settings, struct settings *parent ) {
182
183         /* NULL parent => add to settings root */
184         assert ( settings != NULL );
185         if ( parent == NULL )
186                 parent = &settings_root;
187
188         /* Add to list of settings */
189         ref_get ( settings->refcnt );
190         ref_get ( parent->refcnt );
191         settings->parent = parent;
192         list_add_tail ( &settings->siblings, &parent->children );
193         DBGC ( settings, "Settings %p registered\n", settings );
194
195         /* Fix up settings priority */
196         reprioritise_settings ( settings );
197
198         /* Apply potentially-updated settings */
199         apply_settings();
200
201         return 0;
202 }
203
204 /**
205  * Unregister settings block
206  *
207  * @v settings          Settings block
208  */
209 void unregister_settings ( struct settings *settings ) {
210
211         /* Remove from list of settings */
212         ref_put ( settings->refcnt );
213         ref_put ( settings->parent->refcnt );
214         settings->parent = NULL;
215         list_del ( &settings->siblings );
216         DBGC ( settings, "Settings %p unregistered\n", settings );
217
218         /* Apply potentially-updated settings */
219         apply_settings();
220 }
221
222 /**
223  * Find child named settings block
224  *
225  * @v parent            Parent settings block
226  * @v name              Name within this parent
227  * @ret settings        Settings block, or NULL
228  */
229 struct settings * find_child_settings ( struct settings *parent,
230                                         const char *name ) {
231         struct settings *settings;
232         size_t len;
233
234         /* Look for a child whose name matches the initial component */
235         list_for_each_entry ( settings, &parent->children, siblings ) {
236                 len = strlen ( settings->name );
237                 if ( strncmp ( name, settings->name, len ) != 0 )
238                         continue;
239                 if ( name[len] == 0 )
240                         return settings;
241                 if ( name[len] == '.' )
242                         return find_child_settings ( settings,
243                                                      ( name + len + 1 ) );
244         }
245
246         return NULL;
247 }
248
249 /**
250  * Find named settings block
251  *
252  * @v name              Name
253  * @ret settings        Settings block, or NULL
254  */
255 struct settings * find_settings ( const char *name ) {
256
257         /* If name is empty, use the root */
258         if ( ! *name )
259                 return &settings_root;
260
261         return find_child_settings ( &settings_root, name );
262 }
263
264 /******************************************************************************
265  *
266  * Core settings routines
267  *
268  ******************************************************************************
269  */
270
271 /**
272  * Store value of setting
273  *
274  * @v settings          Settings block
275  * @v tag               Setting tag number
276  * @v data              Setting data, or NULL to clear setting
277  * @v len               Length of setting data
278  * @ret rc              Return status code
279  */
280 int store_setting ( struct settings *settings, unsigned int tag,
281                     const void *data, size_t len ) {
282         struct settings *parent;
283         int rc;
284
285         /* Sanity check */
286         if ( ! settings )
287                 return -ENODEV;
288
289         /* Store setting */
290         if ( ( rc = settings->op->store ( settings, tag, data, len ) ) != 0 )
291                 return rc;
292
293         /* Reprioritise settings if necessary */
294         if ( tag == DHCP_EB_PRIORITY )
295                 reprioritise_settings ( settings );
296
297         /* If these settings are registered, apply potentially-updated
298          * settings
299          */
300         for ( parent = settings->parent ; parent ; parent = parent->parent ) {
301                 if ( parent == &settings_root ) {
302                         if ( ( rc = apply_settings() ) != 0 )
303                                 return rc;
304                         break;
305                 }
306         }
307
308         return 0;
309 }
310
311 /**
312  * Fetch value of setting
313  *
314  * @v settings          Settings block, or NULL to search all blocks
315  * @v tag               Setting tag number
316  * @v data              Buffer to fill with setting data
317  * @v len               Length of buffer
318  * @ret len             Length of setting data, or negative error
319  *
320  * The actual length of the setting will be returned even if
321  * the buffer was too small.
322  */
323 int fetch_setting ( struct settings *settings, unsigned int tag,
324                     void *data, size_t len ) {
325         struct settings *child;
326         int ret;
327
328         /* NULL settings implies starting at the global settings root */
329         if ( ! settings )
330                 settings = &settings_root;
331
332         /* Try this block first */
333         if ( ( ret = settings->op->fetch ( settings, tag, data, len ) ) >= 0)
334                 return ret;
335
336         /* Recurse into each child block in turn */
337         list_for_each_entry ( child, &settings->children, siblings ) {
338                 if ( ( ret = fetch_setting ( child, tag, data, len ) ) >= 0)
339                         return ret;
340         }
341
342         return -ENOENT;
343 }
344
345 /**
346  * Fetch length of setting
347  *
348  * @v settings          Settings block, or NULL to search all blocks
349  * @v tag               Setting tag number
350  * @ret len             Length of setting data, or negative error
351  *
352  * This function can also be used as an existence check for the
353  * setting.
354  */
355 int fetch_setting_len ( struct settings *settings, unsigned int tag ) {
356         return fetch_setting ( settings, tag, NULL, 0 );
357 }
358
359 /**
360  * Fetch value of string setting
361  *
362  * @v settings          Settings block, or NULL to search all blocks
363  * @v tag               Setting tag number
364  * @v data              Buffer to fill with setting string data
365  * @v len               Length of buffer
366  * @ret len             Length of string setting, or negative error
367  *
368  * The resulting string is guaranteed to be correctly NUL-terminated.
369  * The returned length will be the length of the underlying setting
370  * data.
371  */
372 int fetch_string_setting ( struct settings *settings, unsigned int tag,
373                            char *data, size_t len ) {
374         memset ( data, 0, len );
375         return fetch_setting ( settings, tag, data, ( len - 1 ) );
376 }
377
378 /**
379  * Fetch value of IPv4 address setting
380  *
381  * @v settings          Settings block, or NULL to search all blocks
382  * @v tag               Setting tag number
383  * @v inp               IPv4 address to fill in
384  * @ret len             Length of setting, or negative error
385  */
386 int fetch_ipv4_setting ( struct settings *settings, unsigned int tag,
387                          struct in_addr *inp ) {
388         int len;
389
390         len = fetch_setting ( settings, tag, inp, sizeof ( *inp ) );
391         if ( len < 0 )
392                 return len;
393         if ( len < ( int ) sizeof ( *inp ) )
394                 return -ERANGE;
395         return len;
396 }
397
398 /**
399  * Fetch value of signed integer setting
400  *
401  * @v settings          Settings block, or NULL to search all blocks
402  * @v tag               Setting tag number
403  * @v value             Integer value to fill in
404  * @ret len             Length of setting, or negative error
405  */
406 int fetch_int_setting ( struct settings *settings, unsigned int tag,
407                         long *value ) {
408         union {
409                 long value;
410                 uint8_t u8[ sizeof ( long ) ];
411                 int8_t s8[ sizeof ( long ) ];
412         } buf;
413         int len;
414         int i;
415
416         buf.value = 0;
417         len = fetch_setting ( settings, tag, &buf, sizeof ( buf ) );
418         if ( len < 0 )
419                 return len;
420         if ( len > ( int ) sizeof ( buf ) )
421                 return -ERANGE;
422
423         *value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
424         for ( i = 0 ; i < len ; i++ ) {
425                 *value = ( ( *value << 8 ) | buf.u8[i] );
426         }
427
428         return len;
429 }
430
431 /**
432  * Fetch value of unsigned integer setting
433  *
434  * @v settings          Settings block, or NULL to search all blocks
435  * @v tag               Setting tag number
436  * @v value             Integer value to fill in
437  * @ret len             Length of setting, or negative error
438  */
439 int fetch_uint_setting ( struct settings *settings, unsigned int tag,
440                          unsigned long *value ) {
441         long svalue;
442         int len;
443
444         len = fetch_int_setting ( settings, tag, &svalue );
445         if ( len < 0 )
446                 return len;
447
448         *value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) );
449
450         return len;
451 }
452
453 /**
454  * Fetch value of signed integer setting, or zero
455  *
456  * @v settings          Settings block, or NULL to search all blocks
457  * @v tag               Setting tag number
458  * @ret value           Setting value, or zero
459  */
460 long fetch_intz_setting ( struct settings *settings, unsigned int tag ) {
461         long value = 0;
462
463         fetch_int_setting ( settings, tag, &value );
464         return value;
465 }
466
467 /**
468  * Fetch value of unsigned integer setting, or zero
469  *
470  * @v settings          Settings block, or NULL to search all blocks
471  * @v tag               Setting tag number
472  * @ret value           Setting value, or zero
473  */
474 unsigned long fetch_uintz_setting ( struct settings *settings,
475                                     unsigned int tag ) {
476         unsigned long value = 0;
477
478         fetch_uint_setting ( settings, tag, &value );
479         return value;
480 }
481
482 /**
483  * Copy setting
484  *
485  * @v dest              Destination settings block
486  * @v dest_tag          Destination setting tag number
487  * @v source            Source settings block
488  * @v source_tag        Source setting tag number
489  * @ret rc              Return status code
490  */
491 int copy_setting ( struct settings *dest, unsigned int dest_tag,
492                    struct settings *source, unsigned int source_tag ) {
493         int len;
494         int check_len;
495         int rc;
496
497         len = fetch_setting_len ( source, source_tag );
498         if ( len < 0 )
499                 return len;
500
501         {
502                 char buf[len];
503
504                 check_len = fetch_setting ( source, source_tag, buf,
505                                             sizeof ( buf ) );
506                 assert ( check_len == len );
507
508                 if ( ( rc = store_setting ( dest, dest_tag, buf,
509                                             sizeof ( buf ) ) ) != 0 )
510                         return rc;
511         }
512
513         return 0;
514 }
515
516 /**
517  * Copy settings
518  *
519  * @v dest              Destination settings block
520  * @v source            Source settings block
521  * @v encapsulator      Encapsulating setting tag number, or zero
522  * @ret rc              Return status code
523  */
524 static int copy_encap_settings ( struct settings *dest,
525                                  struct settings *source,
526                                  unsigned int encapsulator ) {
527         unsigned int subtag;
528         unsigned int tag;
529         int rc;
530
531         for ( subtag = DHCP_MIN_OPTION; subtag <= DHCP_MAX_OPTION; subtag++ ) {
532                 tag = DHCP_ENCAP_OPT ( encapsulator, subtag );
533                 switch ( tag ) {
534                 case DHCP_EB_ENCAP:
535                 case DHCP_VENDOR_ENCAP:
536                         /* Process encapsulated options field */
537                         if ( ( rc = copy_encap_settings ( dest, source,
538                                                           tag ) ) != 0 )
539                                 return rc;
540                         break;
541                 default:
542                         /* Copy option to reassembled packet */
543                         if ( ( rc = copy_setting ( dest, tag, source,
544                                                    tag ) ) != 0 )
545                                 return rc;
546                         break;
547                 }
548         }
549
550         return 0;
551 }
552
553 /**
554  * Copy settings
555  *
556  * @v dest              Destination settings block
557  * @v source            Source settings block
558  * @ret rc              Return status code
559  */
560 int copy_settings ( struct settings *dest, struct settings *source ) {
561         return copy_encap_settings ( dest, source, 0 );
562 }
563
564 /******************************************************************************
565  *
566  * Named and typed setting routines
567  *
568  ******************************************************************************
569  */
570
571 /**
572  * Store value of typed setting
573  *
574  * @v settings          Settings block
575  * @v tag               Setting tag number
576  * @v type              Settings type
577  * @v value             Formatted setting data, or NULL
578  * @ret rc              Return status code
579  */
580 int store_typed_setting ( struct settings *settings,
581                           unsigned int tag, struct setting_type *type,
582                           const char *value ) {
583
584         /* NULL value implies deletion.  Avoid imposing the burden of
585          * checking for NULL values on each typed setting's storef()
586          * method.
587          */
588         if ( ! value )
589                 return delete_setting ( settings, tag );
590                 
591         return type->storef ( settings, tag, value );
592 }
593
594 /**
595  * Find named setting
596  *
597  * @v name              Name
598  * @ret setting         Named setting, or NULL
599  */
600 static struct named_setting * find_named_setting ( const char *name ) {
601         struct named_setting *setting;
602
603         for ( setting = named_settings ; setting < named_settings_end ;
604               setting++ ) {
605                 if ( strcmp ( name, setting->name ) == 0 )
606                         return setting;
607         }
608         return NULL;
609 }
610
611 /**
612  * Find setting type
613  *
614  * @v name              Name
615  * @ret type            Setting type, or NULL
616  */
617 static struct setting_type * find_setting_type ( const char *name ) {
618         struct setting_type *type;
619
620         for ( type = setting_types ; type < setting_types_end ; type++ ) {
621                 if ( strcmp ( name, type->name ) == 0 )
622                         return type;
623         }
624         return NULL;
625 }
626
627 /**
628  * Parse setting name
629  *
630  * @v name              Name of setting
631  * @ret settings        Settings block, or NULL
632  * @ret tag             Setting tag number
633  * @ret type            Setting type
634  * @ret rc              Return status code
635  *
636  * Interprets a name of the form
637  * "[settings_name/]tag_name[:type_name]" and fills in the appropriate
638  * fields.
639  */
640 static int parse_setting_name ( const char *name, struct settings **settings,
641                                 unsigned int *tag,
642                                 struct setting_type **type ) {
643         char tmp_name[ strlen ( name ) + 1 ];
644         char *settings_name;
645         char *tag_name;
646         char *type_name;
647         struct named_setting *named_setting;
648         char *tmp;
649
650         /* Set defaults */
651         *settings = &settings_root;
652         *tag = 0;
653         *type = &setting_type_hex;
654
655         /* Split name into "[settings_name/]tag_name[:type_name]" */
656         memcpy ( tmp_name, name, sizeof ( tmp_name ) );
657         if ( ( tag_name = strchr ( tmp_name, '/' ) ) != NULL ) {
658                 *(tag_name++) = 0;
659                 settings_name = tmp_name;
660         } else {
661                 tag_name = tmp_name;
662                 settings_name = NULL;
663         }
664         if ( ( type_name = strchr ( tag_name, ':' ) ) != NULL )
665                 *(type_name++) = 0;
666
667         /* Identify settings block, if specified */
668         if ( settings_name ) {
669                 *settings = find_settings ( settings_name );
670                 if ( *settings == NULL ) {
671                         DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n",
672                               settings_name, name );
673                         return -ENODEV;
674                 }
675         }
676
677         /* Identify tag number */
678         if ( ( named_setting = find_named_setting ( tag_name ) ) != NULL ) {
679                 *tag = named_setting->tag;
680                 *type = named_setting->type;
681         } else {
682                 /* Unrecognised name: try to interpret as a tag number */
683                 tmp = tag_name;
684                 while ( 1 ) {
685                         *tag = ( ( *tag << 8 ) | strtoul ( tmp, &tmp, 0 ) );
686                         if ( *tmp == 0 )
687                                 break;
688                         if ( *tmp != '.' ) {
689                                 DBG ( "Invalid tag number \"%s\" in \"%s\"\n",
690                                       tag_name, name );
691                                 return -ENOENT;
692                         }
693                         tmp++;
694                 }
695         }
696
697         /* Identify setting type, if specified */
698         if ( type_name ) {
699                 *type = find_setting_type ( type_name );
700                 if ( *type == NULL ) {
701                         DBG ( "Invalid setting type \"%s\" in \"%s\"\n",
702                               type_name, name );
703                         return -ENOTSUP;
704                 }
705         }
706
707         return 0;
708 }
709
710 /**
711  * Parse and store value of named setting
712  *
713  * @v name              Name of setting
714  * @v value             Formatted setting data, or NULL
715  * @ret rc              Return status code
716  */
717 int store_named_setting ( const char *name, const char *value ) {
718         struct settings *settings;
719         unsigned int tag;
720         struct setting_type *type;
721         int rc;
722
723         if ( ( rc = parse_setting_name ( name, &settings, &tag,
724                                          &type ) ) != 0 )
725                 return rc;
726         return store_typed_setting ( settings, tag, type, value );
727 }
728
729 /**
730  * Fetch and format value of named setting
731  *
732  * @v name              Name of setting
733  * @v buf               Buffer to contain formatted value
734  * @v len               Length of buffer
735  * @ret len             Length of formatted value, or negative error
736  */
737 int fetch_named_setting ( const char *name, char *buf, size_t len ) {
738         struct settings *settings;
739         unsigned int tag;
740         struct setting_type *type;
741         int rc;
742
743         if ( ( rc = parse_setting_name ( name, &settings, &tag,
744                                          &type ) ) != 0 )
745                 return rc;
746         return fetch_typed_setting ( settings, tag, type, buf, len );
747 }
748
749 /******************************************************************************
750  *
751  * Setting types
752  *
753  ******************************************************************************
754  */
755
756 /**
757  * Parse and store value of string setting
758  *
759  * @v settings          Settings block
760  * @v tag               Setting tag number
761  * @v value             Formatted setting data
762  * @ret rc              Return status code
763  */
764 static int storef_string ( struct settings *settings, unsigned int tag,
765                            const char *value ) {
766         return store_setting ( settings, tag, value, strlen ( value ) );
767 }
768
769 /**
770  * Fetch and format value of string setting
771  *
772  * @v settings          Settings block, or NULL to search all blocks
773  * @v tag               Setting tag number
774  * @v buf               Buffer to contain formatted value
775  * @v len               Length of buffer
776  * @ret len             Length of formatted value, or negative error
777  */
778 static int fetchf_string ( struct settings *settings, unsigned int tag,
779                            char *buf, size_t len ) {
780         return fetch_string_setting ( settings, tag, buf, len );
781 }
782
783 /** A string setting type */
784 struct setting_type setting_type_string __setting_type = {
785         .name = "string",
786         .storef = storef_string,
787         .fetchf = fetchf_string,
788 };
789
790 /**
791  * Parse and store value of IPv4 address setting
792  *
793  * @v settings          Settings block
794  * @v tag               Setting tag number
795  * @v value             Formatted setting data
796  * @ret rc              Return status code
797  */
798 static int storef_ipv4 ( struct settings *settings, unsigned int tag,
799                          const char *value ) {
800         struct in_addr ipv4;
801
802         if ( inet_aton ( value, &ipv4 ) == 0 )
803                 return -EINVAL;
804         return store_setting ( settings, tag, &ipv4, sizeof ( ipv4 ) );
805 }
806
807 /**
808  * Fetch and format value of IPv4 address setting
809  *
810  * @v settings          Settings block, or NULL to search all blocks
811  * @v tag               Setting tag number
812  * @v buf               Buffer to contain formatted value
813  * @v len               Length of buffer
814  * @ret len             Length of formatted value, or negative error
815  */
816 static int fetchf_ipv4 ( struct settings *settings, unsigned int tag,
817                          char *buf, size_t len ) {
818         struct in_addr ipv4;
819         int rc;
820
821         if ( ( rc = fetch_ipv4_setting ( settings, tag, &ipv4 ) ) < 0 )
822                 return rc;
823         return snprintf ( buf, len, inet_ntoa ( ipv4 ) );
824 }
825
826 /** An IPv4 address setting type */
827 struct setting_type setting_type_ipv4 __setting_type = {
828         .name = "ipv4",
829         .storef = storef_ipv4,
830         .fetchf = fetchf_ipv4,
831 };
832
833 /**
834  * Parse and store value of integer setting
835  *
836  * @v settings          Settings block
837  * @v tag               Setting tag number
838  * @v value             Formatted setting data
839  * @v size              Integer size, in bytes
840  * @ret rc              Return status code
841  */
842 static int storef_int ( struct settings *settings, unsigned int tag,
843                         const char *value, unsigned int size ) {
844         union {
845                 uint32_t num;
846                 uint8_t bytes[4];
847         } u;
848         char *endp;
849
850         u.num = htonl ( strtoul ( value, &endp, 0 ) );
851         if ( *endp )
852                 return -EINVAL;
853         return store_setting ( settings, tag, 
854                                &u.bytes[ sizeof ( u ) - size ], size );
855 }
856
857 /**
858  * Parse and store value of 8-bit integer setting
859  *
860  * @v settings          Settings block
861  * @v tag               Setting tag number
862  * @v value             Formatted setting data
863  * @v size              Integer size, in bytes
864  * @ret rc              Return status code
865  */
866 static int storef_int8 ( struct settings *settings, unsigned int tag,
867                          const char *value ) {
868         return storef_int ( settings, tag, value, 1 );
869 }
870
871 /**
872  * Parse and store value of 16-bit integer setting
873  *
874  * @v settings          Settings block
875  * @v tag               Setting tag number
876  * @v value             Formatted setting data
877  * @v size              Integer size, in bytes
878  * @ret rc              Return status code
879  */
880 static int storef_int16 ( struct settings *settings, unsigned int tag,
881                           const char *value ) {
882         return storef_int ( settings, tag, value, 2 );
883 }
884
885 /**
886  * Parse and store value of 32-bit integer setting
887  *
888  * @v settings          Settings block
889  * @v tag               Setting tag number
890  * @v value             Formatted setting data
891  * @v size              Integer size, in bytes
892  * @ret rc              Return status code
893  */
894 static int storef_int32 ( struct settings *settings, unsigned int tag,
895                           const char *value ) {
896         return storef_int ( settings, tag, value, 4 );
897 }
898
899 /**
900  * Fetch and format value of signed integer setting
901  *
902  * @v settings          Settings block, or NULL to search all blocks
903  * @v tag               Setting tag number
904  * @v buf               Buffer to contain formatted value
905  * @v len               Length of buffer
906  * @ret len             Length of formatted value, or negative error
907  */
908 static int fetchf_int ( struct settings *settings, unsigned int tag,
909                         char *buf, size_t len ) {
910         long value;
911         int rc;
912
913         if ( ( rc = fetch_int_setting ( settings, tag, &value ) ) < 0 )
914                 return rc;
915         return snprintf ( buf, len, "%ld", value );
916 }
917
918 /**
919  * Fetch and format value of unsigned integer setting
920  *
921  * @v settings          Settings block, or NULL to search all blocks
922  * @v tag               Setting tag number
923  * @v buf               Buffer to contain formatted value
924  * @v len               Length of buffer
925  * @ret len             Length of formatted value, or negative error
926  */
927 static int fetchf_uint ( struct settings *settings, unsigned int tag,
928                          char *buf, size_t len ) {
929         unsigned long value;
930         int rc;
931
932         if ( ( rc = fetch_uint_setting ( settings, tag, &value ) ) < 0 )
933                 return rc;
934         return snprintf ( buf, len, "%#lx", value );
935 }
936
937 /** A signed 8-bit integer setting type */
938 struct setting_type setting_type_int8 __setting_type = {
939         .name = "int8",
940         .storef = storef_int8,
941         .fetchf = fetchf_int,
942 };
943
944 /** A signed 16-bit integer setting type */
945 struct setting_type setting_type_int16 __setting_type = {
946         .name = "int16",
947         .storef = storef_int16,
948         .fetchf = fetchf_int,
949 };
950
951 /** A signed 32-bit integer setting type */
952 struct setting_type setting_type_int32 __setting_type = {
953         .name = "int32",
954         .storef = storef_int32,
955         .fetchf = fetchf_int,
956 };
957
958 /** An unsigned 8-bit integer setting type */
959 struct setting_type setting_type_uint8 __setting_type = {
960         .name = "uint8",
961         .storef = storef_int8,
962         .fetchf = fetchf_uint,
963 };
964
965 /** An unsigned 16-bit integer setting type */
966 struct setting_type setting_type_uint16 __setting_type = {
967         .name = "uint16",
968         .storef = storef_int16,
969         .fetchf = fetchf_uint,
970 };
971
972 /** An unsigned 32-bit integer setting type */
973 struct setting_type setting_type_uint32 __setting_type = {
974         .name = "uint32",
975         .storef = storef_int32,
976         .fetchf = fetchf_uint,
977 };
978
979 /**
980  * Parse and store value of hex string setting
981  *
982  * @v settings          Settings block
983  * @v tag               Setting tag number
984  * @v value             Formatted setting data
985  * @ret rc              Return status code
986  */
987 static int storef_hex ( struct settings *settings, unsigned int tag,
988                         const char *value ) {
989         char *ptr = ( char * ) value;
990         uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
991         unsigned int len = 0;
992
993         while ( 1 ) {
994                 bytes[len++] = strtoul ( ptr, &ptr, 16 );
995                 switch ( *ptr ) {
996                 case '\0' :
997                         return store_setting ( settings, tag, bytes, len );
998                 case ':' :
999                         ptr++;
1000                         break;
1001                 default :
1002                         return -EINVAL;
1003                 }
1004         }
1005 }
1006
1007 /**
1008  * Fetch and format value of hex string setting
1009  *
1010  * @v settings          Settings block, or NULL to search all blocks
1011  * @v tag               Setting tag number
1012  * @v buf               Buffer to contain formatted value
1013  * @v len               Length of buffer
1014  * @ret len             Length of formatted value, or negative error
1015  */
1016 static int fetchf_hex ( struct settings *settings, unsigned int tag,
1017                         char *buf, size_t len ) {
1018         int raw_len;
1019         int check_len;
1020         int used = 0;
1021         int i;
1022
1023         raw_len = fetch_setting_len ( settings, tag );
1024         if ( raw_len < 0 )
1025                 return raw_len;
1026
1027         {
1028                 uint8_t raw[raw_len];
1029
1030                 check_len = fetch_setting ( settings, tag, raw, sizeof (raw) );
1031                 assert ( check_len == raw_len );
1032                 
1033                 if ( len )
1034                         buf[0] = 0; /* Ensure that a terminating NUL exists */
1035                 for ( i = 0 ; i < raw_len ; i++ ) {
1036                         used += ssnprintf ( ( buf + used ), ( len - used ),
1037                                             "%s%02x", ( used ? ":" : "" ),
1038                                             raw[i] );
1039                 }
1040                 return used;
1041         }
1042 }
1043
1044 /** A hex-string setting */
1045 struct setting_type setting_type_hex __setting_type = {
1046         .name = "hex",
1047         .storef = storef_hex,
1048         .fetchf = fetchf_hex,
1049 };
1050
1051 /******************************************************************************
1052  *
1053  * Named settings
1054  *
1055  ******************************************************************************
1056  */
1057
1058 /** Some basic setting definitions */
1059 struct named_setting basic_named_settings[] __named_setting = {
1060         {
1061                 .name = "ip",
1062                 .description = "IPv4 address",
1063                 .tag = DHCP_EB_YIADDR,
1064                 .type = &setting_type_ipv4,
1065         },
1066         {
1067                 .name = "netmask",
1068                 .description = "IPv4 subnet mask",
1069                 .tag = DHCP_SUBNET_MASK,
1070                 .type = &setting_type_ipv4,
1071         },
1072         {
1073                 .name = "gateway",
1074                 .description = "Default gateway",
1075                 .tag = DHCP_ROUTERS,
1076                 .type = &setting_type_ipv4,
1077         },
1078         {
1079                 .name = "dns",
1080                 .description = "DNS server",
1081                 .tag = DHCP_DNS_SERVERS,
1082                 .type = &setting_type_ipv4,
1083         },
1084         {
1085                 .name = "hostname",
1086                 .description = "Host name",
1087                 .tag = DHCP_HOST_NAME,
1088                 .type = &setting_type_string,
1089         },
1090         {
1091                 .name = "filename",
1092                 .description = "Boot filename",
1093                 .tag = DHCP_BOOTFILE_NAME,
1094                 .type = &setting_type_string,
1095         },
1096         {
1097                 .name = "root-path",
1098                 .description = "NFS/iSCSI root path",
1099                 .tag = DHCP_ROOT_PATH,
1100                 .type = &setting_type_string,
1101         },
1102         {
1103                 .name = "username",
1104                 .description = "User name",
1105                 .tag = DHCP_EB_USERNAME,
1106                 .type = &setting_type_string,
1107         },
1108         {
1109                 .name = "password",
1110                 .description = "Password",
1111                 .tag = DHCP_EB_PASSWORD,
1112                 .type = &setting_type_string,
1113         },
1114         {
1115                 .name = "initiator-iqn",
1116                 .description = "iSCSI initiator name",
1117                 .tag = DHCP_ISCSI_INITIATOR_IQN,
1118                 .type = &setting_type_string,
1119         },
1120         {
1121                 .name = "priority",
1122                 .description = "Priority of these settings",
1123                 .tag = DHCP_EB_PRIORITY,
1124                 .type = &setting_type_int8,
1125         },
1126 };