[Settings] Introduce settings applicators.
[people/dverkamp/gpxe.git] / src / net / dhcpopts.c
index c906b19..75a9f2a 100644 (file)
  */
 
 #include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
 #include <byteswap.h>
 #include <errno.h>
 #include <string.h>
-#include <malloc.h>
 #include <assert.h>
-#include <vsprintf.h>
 #include <gpxe/list.h>
 #include <gpxe/in.h>
+#include <gpxe/uri.h>
 #include <gpxe/dhcp.h>
 
 /** @file
@@ -34,7 +35,7 @@
  */
 
 /** List of registered DHCP option blocks */
-static LIST_HEAD ( option_blocks );
+LIST_HEAD ( dhcp_option_blocks );
 
 /**
  * Obtain printable version of a DHCP option tag
@@ -252,7 +253,7 @@ struct dhcp_option * find_dhcp_option ( struct dhcp_option_block *options,
        if ( options ) {
                return find_dhcp_option_with_encap ( options, tag, NULL );
        } else {
-               list_for_each_entry ( options, &option_blocks, list ) {
+               list_for_each_entry ( options, &dhcp_option_blocks, list ) {
                        if ( ( option = find_dhcp_option ( options, tag ) ) )
                                return option;
                }
@@ -276,11 +277,15 @@ void register_dhcp_options ( struct dhcp_option_block *options ) {
              options, options->priority );
 
        /* Insert after any existing blocks which have a higher priority */
-       list_for_each_entry ( existing, &option_blocks, list ) {
+       list_for_each_entry ( existing, &dhcp_option_blocks, list ) {
                if ( options->priority > existing->priority )
                        break;
        }
+       dhcpopt_get ( options );
        list_add_tail ( &options->list, &existing->list );
+
+       /* Apply all registered DHCP options */
+       apply_global_dhcp_options();
 }
 
 /**
@@ -290,6 +295,7 @@ void register_dhcp_options ( struct dhcp_option_block *options ) {
  */
 void unregister_dhcp_options ( struct dhcp_option_block *options ) {
        list_del ( &options->list );
+       dhcpopt_put ( options );
 }
 
 /**
@@ -337,15 +343,6 @@ struct dhcp_option_block * alloc_dhcp_options ( size_t max_len ) {
        return options;
 }
 
-/**
- * Free DHCP options block
- *
- * @v options          DHCP option block
- */
-void free_dhcp_options ( struct dhcp_option_block *options ) {
-       free ( options );
-}
-
 /**
  * Resize a DHCP option
  *
@@ -409,25 +406,30 @@ struct dhcp_option * set_dhcp_option ( struct dhcp_option_block *options,
                                       const void *data, size_t len ) {
        static const uint8_t empty_encapsulator[] = { DHCP_END };
        struct dhcp_option *option;
-       void *insertion_point = options->data;
+       void *insertion_point;
        struct dhcp_option *encapsulator = NULL;
        unsigned int encap_tag = DHCP_ENCAPSULATOR ( tag );
        size_t old_len = 0;
        size_t new_len = ( len ? ( len + DHCP_OPTION_HEADER_LEN ) : 0 );
 
+       /* Return NULL if no options block specified */
+       if ( ! options )
+               return NULL;
+
        /* Find old instance of this option, if any */
        option = find_dhcp_option_with_encap ( options, tag, &encapsulator );
        if ( option ) {
                old_len = dhcp_option_len ( option );
-               DBG ( "Resizing DHCP option %s from length %d to %d in block "
+               DBG ( "Resizing DHCP option %s from length %d to %zd in block "
                      "%p\n", dhcp_tag_name (tag), option->len, len, options );
        } else {
                old_len = 0;
-               DBG ( "Creating DHCP option %s (length %d) in block %p\n",
+               DBG ( "Creating DHCP option %s (length %zd) in block %p\n",
                      dhcp_tag_name ( tag ), len, options );
        }
        
        /* Ensure that encapsulator exists, if required */
+       insertion_point = options->data;
        if ( DHCP_IS_ENCAP_OPT ( tag ) ) {
                if ( ! encapsulator )
                        encapsulator = set_dhcp_option ( options, encap_tag,
@@ -562,3 +564,36 @@ void delete_dhcp_option ( struct dhcp_option_block *options,
                          unsigned int tag ) {
        set_dhcp_option ( options, tag, NULL, 0 );
 }
+
+/**
+ * Apply DHCP options
+ *
+ * @v options          DHCP options block, or NULL
+ * @ret rc             Return status code
+ */
+int apply_dhcp_options ( struct dhcp_option_block *options ) {
+       struct in_addr tftp_server;
+       struct uri *uri;
+       char uri_string[32];
+
+       /* Set current working URI based on TFTP server */
+       find_dhcp_ipv4_option ( options, DHCP_EB_SIADDR, &tftp_server );
+       snprintf ( uri_string, sizeof ( uri_string ),
+                  "tftp://%s/", inet_ntoa ( tftp_server ) );
+       uri = parse_uri ( uri_string );
+       if ( ! uri )
+               return -ENOMEM;
+       churi ( uri );
+       uri_put ( uri );
+
+       return 0;
+}
+
+/**
+ * Apply global DHCP options
+ *
+ * @ret rc             Return status code
+ */
+int apply_global_dhcp_options ( void ) {
+       return apply_dhcp_options ( NULL );
+}