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