diff --git a/src/include/gpxe/dhcp.h b/src/include/gpxe/dhcp.h index 3183a3a9..caac9144 100644 --- a/src/include/gpxe/dhcp.h +++ b/src/include/gpxe/dhcp.h @@ -11,6 +11,7 @@ #include #include #include +#include struct net_device; struct job_interface; @@ -438,6 +439,23 @@ struct dhcp_packet { struct dhcp_option_block options; }; +/** A DHCP option applicator */ +struct dhcp_option_applicator { + /** DHCP option tag */ + unsigned int tag; + /** Applicator + * + * @v tag DHCP option tag + * @v option DHCP option + * @ret rc Return status code + */ + int ( * apply ) ( unsigned int tag, struct dhcp_option *option ); +}; + +/** Declare a DHCP option applicator */ +#define __dhcp_applicator \ + __table ( struct dhcp_option_applicator, dhcp_appicators, 01 ) + /** * Get reference to DHCP options block * @@ -485,6 +503,7 @@ extern void find_global_dhcp_ipv4_option ( unsigned int tag, struct in_addr *inp ); extern void delete_dhcp_option ( struct dhcp_option_block *options, unsigned int tag ); +extern int apply_dhcp_options ( struct dhcp_option_block *options ); extern struct dhcp_option_block dhcp_request_options; extern int create_dhcp_packet ( struct net_device *netdev, uint8_t msgtype, diff --git a/src/net/dhcpopts.c b/src/net/dhcpopts.c index bb977317..6038709b 100644 --- a/src/net/dhcpopts.c +++ b/src/net/dhcpopts.c @@ -25,6 +25,7 @@ #include #include #include +#include #include /** @file @@ -36,6 +37,12 @@ /** List of registered DHCP option blocks */ static LIST_HEAD ( option_blocks ); +/** Registered DHCP option applicators */ +static struct dhcp_option_applicator dhcp_option_applicators[0] + __table_start ( struct dhcp_option_applicator, dhcp_applicators ); +static struct dhcp_option_applicator dhcp_option_applicators_end[0] + __table_end ( struct dhcp_option_applicator, dhcp_applicators ); + /** * Obtain printable version of a DHCP option tag * @@ -560,3 +567,45 @@ 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 dhcp_option_applicator *applicator; + struct dhcp_option *option; + struct in_addr tftp_server; + struct uri *uri; + char uri_string[32]; + unsigned int tag; + int rc; + + /* 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 ); + + /* Call all registered DHCP option applicators */ + for ( applicator = dhcp_option_applicators ; + applicator < dhcp_option_applicators_end ; applicator++ ) { + tag = applicator->tag; + option = find_dhcp_option ( options, tag ); + if ( ! option ) + continue; + if ( ( rc = applicator->apply ( tag, option ) ) != 0 ) { + DBG ( "Could not apply DHCP option %s: %s\n", + dhcp_tag_name ( tag ), strerror ( rc ) ); + return rc; + } + } + + return 0; +} diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index 03e6c9d9..a8cb9376 100644 --- a/src/net/udp/dhcp.c +++ b/src/net/udp/dhcp.c @@ -30,7 +30,6 @@ #include #include #include -#include #include /** @file @@ -826,12 +825,6 @@ int start_dhcp ( struct job_interface *job, struct net_device *netdev, * */ -/* Avoid dragging in dns.o */ -struct sockaddr_tcpip nameserver; - -/* Avoid dragging in syslog.o */ -struct in_addr syslogserver; - /** * Configure network device from DHCP options * @@ -844,10 +837,6 @@ int dhcp_configure_netdev ( struct net_device *netdev, struct in_addr address = { 0 }; struct in_addr netmask = { 0 }; struct in_addr gateway = { INADDR_NONE }; - struct sockaddr_in *sin_nameserver; - struct in_addr tftp_server; - struct uri *uri; - char uri_string[32]; int rc; /* Clear any existing routing table entry */ @@ -866,23 +855,12 @@ int dhcp_configure_netdev ( struct net_device *netdev, return rc; } - /* Retrieve other DHCP options that we care about */ - sin_nameserver = ( struct sockaddr_in * ) &nameserver; - sin_nameserver->sin_family = AF_INET; - find_dhcp_ipv4_option ( options, DHCP_DNS_SERVERS, - &sin_nameserver->sin_addr ); - find_dhcp_ipv4_option ( options, DHCP_LOG_SERVERS, - &syslogserver ); - - /* 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 ); + /* Apply other DHCP options */ + if ( ( rc = apply_dhcp_options ( options ) ) != 0 ) { + DBG ( "Could not apply %s DHCP result options: %s\n", + netdev->name, strerror ( rc ) ); + return rc; + } return 0; } diff --git a/src/net/udp/dns.c b/src/net/udp/dns.c index ff28c7e0..bd519a26 100644 --- a/src/net/udp/dns.c +++ b/src/net/udp/dns.c @@ -30,6 +30,7 @@ #include #include #include +#include #include /** @file @@ -503,3 +504,25 @@ struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = { .name = "DNS", .resolv = dns_resolv, }; + +/** + * Apply DHCP nameserver option + * + * @v tag DHCP option tag + * @v option DHCP option + */ +static int apply_dhcp_nameserver ( unsigned int tag __unused, + struct dhcp_option *option ) { + struct sockaddr_in *sin_nameserver; + + sin_nameserver = ( struct sockaddr_in * ) &nameserver; + sin_nameserver->sin_family = AF_INET; + dhcp_ipv4_option ( option, &sin_nameserver->sin_addr ); + return 0; +} + +/** DHCP nameserver applicator */ +struct dhcp_option_applicator dhcp_nameserver_applicator __dhcp_applicator = { + .tag = DHCP_DNS_SERVERS, + .apply = apply_dhcp_nameserver, +};