diff options
author | Michael Brown <mcb30@etherboot.org> | 2008-03-25 20:46:16 +0000 |
---|---|---|
committer | Michael Brown <mcb30@etherboot.org> | 2008-03-25 20:46:16 +0000 |
commit | 92d15eff30410dcb0ec406e06b131fb7d9179ffd (patch) | |
tree | 191d29013372b541d353bbfa55114b8060dd557c /src/net | |
parent | ee5bdb0d758a953a4f044795a3571ecb5cf3c735 (diff) | |
download | ipxe-92d15eff30410dcb0ec406e06b131fb7d9179ffd.tar.gz |
[Settings] Remove assumption that all settings have DHCP tag values
Allow for settings to be described by something other than a DHCP option
tag if desirable. Currently used only for the MAC address setting.
Separate out fake DHCP packet creation code from dhcp.c to fakedhcp.c.
Remove notion of settings from dhcppkt.c.
Rationalise dhcp.c to use settings API only for final registration of the
DHCP options, rather than using {store,fetch}_setting throughout.
Diffstat (limited to 'src/net')
-rw-r--r-- | src/net/dhcpopts.c | 16 | ||||
-rw-r--r-- | src/net/dhcppkt.c | 30 | ||||
-rw-r--r-- | src/net/fakedhcp.c | 205 | ||||
-rw-r--r-- | src/net/ipv4.c | 143 | ||||
-rw-r--r-- | src/net/netdev_settings.c | 39 | ||||
-rw-r--r-- | src/net/tcp/iscsi.c | 30 | ||||
-rw-r--r-- | src/net/udp/dhcp.c | 303 | ||||
-rw-r--r-- | src/net/udp/dns.c | 17 | ||||
-rw-r--r-- | src/net/udp/tftp.c | 17 |
9 files changed, 503 insertions, 297 deletions
diff --git a/src/net/dhcpopts.c b/src/net/dhcpopts.c index 64b310d4e..1898011aa 100644 --- a/src/net/dhcpopts.c +++ b/src/net/dhcpopts.c @@ -118,6 +118,11 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options, ssize_t remaining = options->len; unsigned int option_len; + /* Sanity check */ + if ( tag == DHCP_PAD ) + return -ENOENT; + + /* Search for option */ while ( remaining ) { /* Calculate length of this option. Abort processing * if the length is malformed (i.e. takes us beyond @@ -128,6 +133,9 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options, remaining -= option_len; if ( remaining < 0 ) break; + /* Check for explicit end marker */ + if ( option->tag == DHCP_END ) + break; /* Check for matching tag */ if ( option->tag == tag ) { DBGC ( options, "DHCPOPT %p found %s (length %d)\n", @@ -135,9 +143,6 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options, option_len ); return offset; } - /* Check for explicit end marker */ - if ( option->tag == DHCP_END ) - break; /* Check for start of matching encapsulation block */ if ( DHCP_IS_ENCAP_OPT ( tag ) && ( option->tag == DHCP_ENCAPSULATOR ( tag ) ) ) { @@ -151,6 +156,7 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options, } offset += option_len; } + return -ENOENT; } @@ -255,6 +261,10 @@ static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag, size_t new_len = ( len ? ( len + DHCP_OPTION_HEADER_LEN ) : 0 ); int rc; + /* Sanity check */ + if ( tag == DHCP_PAD ) + return -ENOTTY; + /* Find old instance of this option, if any */ offset = find_dhcp_option_with_encap ( options, tag, &encap_offset ); if ( offset >= 0 ) { diff --git a/src/net/dhcppkt.c b/src/net/dhcppkt.c index 0a11520f6..1cf99d8d4 100644 --- a/src/net/dhcppkt.c +++ b/src/net/dhcppkt.c @@ -92,20 +92,18 @@ find_dhcp_packet_field ( unsigned int tag ) { } return NULL; } - + /** * Store value of DHCP packet setting * - * @v settings Settings block + * @v dhcppkt DHCP packet * @v tag Setting tag number * @v data Setting data, or NULL to clear setting * @v len Length of setting data * @ret rc Return status code */ -static int dhcppkt_store ( struct settings *settings, unsigned int tag, - const void *data, size_t len ) { - struct dhcp_packet *dhcppkt = - container_of ( settings, struct dhcp_packet, settings ); +int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag, + const void *data, size_t len ) { struct dhcp_packet_field *field; int rc; @@ -131,16 +129,14 @@ static int dhcppkt_store ( struct settings *settings, unsigned int tag, /** * Fetch value of DHCP packet setting * - * @v settings Settings block + * @v dhcppkt DHCP packet * @v tag Setting tag number * @v data Buffer to fill with setting data * @v len Length of buffer * @ret len Length of setting data, or negative error */ -static int dhcppkt_fetch ( struct settings *settings, unsigned int tag, - void *data, size_t len ) { - struct dhcp_packet *dhcppkt = - container_of ( settings, struct dhcp_packet, settings ); +int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag, + void *data, size_t len ) { struct dhcp_packet_field *field; /* If this is a special field, return it */ @@ -156,31 +152,21 @@ static int dhcppkt_fetch ( struct settings *settings, unsigned int tag, return dhcpopt_fetch ( &dhcppkt->options, tag, data, len ); } -/** DHCP settings operations */ -static struct settings_operations dhcppkt_settings_operations = { - .store = dhcppkt_store, - .fetch = dhcppkt_fetch, -}; - /** * Initialise prepopulated DHCP packet * * @v dhcppkt Uninitialised DHCP packet - * @v refcnt Reference counter of containing object, or NULL * @v data Memory for DHCP packet data * @v max_len Length of memory for DHCP packet data * * The memory content must already be filled with valid DHCP options. * A zeroed block counts as a block of valid DHCP options. */ -void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct refcnt *refcnt, - void *data, size_t len ) { +void dhcppkt_init ( struct dhcp_packet *dhcppkt, void *data, size_t len ) { dhcppkt->dhcphdr = data; dhcppkt->max_len = len; dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options, ( len - offsetof ( struct dhcphdr, options ) ) ); dhcppkt->len = ( offsetof ( struct dhcphdr, options ) + dhcppkt->options.len ); - settings_init ( &dhcppkt->settings, &dhcppkt_settings_operations, - refcnt, "dhcp" ); } diff --git a/src/net/fakedhcp.c b/src/net/fakedhcp.c new file mode 100644 index 000000000..c3054db1c --- /dev/null +++ b/src/net/fakedhcp.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <gpxe/settings.h> +#include <gpxe/netdevice.h> +#include <gpxe/dhcppkt.h> +#include <gpxe/fakedhcp.h> + +/** @file + * + * Fake DHCP packets + * + */ + +/** + * Copy settings to DHCP packet + * + * @v dest Destination DHCP packet + * @v source Source settings block + * @v encapsulator Encapsulating setting tag number, or zero + * @ret rc Return status code + */ +static int copy_encap_settings ( struct dhcp_packet *dest, + struct settings *source, + unsigned int encapsulator ) { + struct setting setting = { .name = "" }; + unsigned int subtag; + unsigned int tag; + int len; + int check_len; + int rc; + + for ( subtag = DHCP_MIN_OPTION; subtag <= DHCP_MAX_OPTION; subtag++ ) { + tag = DHCP_ENCAP_OPT ( encapsulator, subtag ); + switch ( tag ) { + case DHCP_EB_ENCAP: + case DHCP_VENDOR_ENCAP: + /* Process encapsulated settings */ + if ( ( rc = copy_encap_settings ( dest, source, + tag ) ) != 0 ) + return rc; + break; + default: + /* Copy setting, if present */ + setting.tag = tag; + len = fetch_setting_len ( source, &setting ); + if ( len < 0 ) + break; + { + char buf[len]; + + check_len = fetch_setting ( source, &setting, + buf, sizeof (buf)); + assert ( check_len == len ); + if ( ( rc = dhcppkt_store ( dest, tag, buf, + sizeof(buf) )) !=0) + return rc; + } + break; + } + } + + return 0; +} + +/** + * Copy settings to DHCP packet + * + * @v dest Destination DHCP packet + * @v source Source settings block + * @ret rc Return status code + */ +static int copy_settings ( struct dhcp_packet *dest, + struct settings *source ) { + return copy_encap_settings ( dest, source, 0 ); +} + +/** + * Create fake DHCPDISCOVER packet + * + * @v netdev Network device + * @v data Buffer for DHCP packet + * @v max_len Size of DHCP packet buffer + * @ret rc Return status code + * + * Used by external code. + */ +int create_fakedhcpdiscover ( struct net_device *netdev, + void *data, size_t max_len ) { + struct dhcp_packet dhcppkt; + int rc; + + if ( ( rc = create_dhcp_request ( &dhcppkt, netdev, NULL, data, + max_len ) ) != 0 ) { + DBG ( "Could not create DHCPDISCOVER: %s\n", + strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Create fake DHCPACK packet + * + * @v netdev Network device + * @v data Buffer for DHCP packet + * @v max_len Size of DHCP packet buffer + * @ret rc Return status code + * + * Used by external code. + */ +int create_fakedhcpack ( struct net_device *netdev, + void *data, size_t max_len ) { + struct dhcp_packet dhcppkt; + int rc; + + /* Create base DHCPACK packet */ + if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL, + data, max_len ) ) != 0 ) { + DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) ); + return rc; + } + + /* Merge in globally-scoped settings, then netdev-specific + * settings. Do it in this order so that netdev-specific + * settings take precedence regardless of stated priorities. + */ + if ( ( rc = copy_settings ( &dhcppkt, NULL ) ) != 0 ) { + DBG ( "Could not set DHCPACK global settings: %s\n", + strerror ( rc ) ); + return rc; + } + if ( ( rc = copy_settings ( &dhcppkt, + netdev_settings ( netdev ) ) ) != 0 ) { + DBG ( "Could not set DHCPACK netdev settings: %s\n", + strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Create ProxyDHCPACK packet + * + * @v netdev Network device + * @v data Buffer for DHCP packet + * @v max_len Size of DHCP packet buffer + * @ret rc Return status code + * + * Used by external code. + */ +int create_fakeproxydhcpack ( struct net_device *netdev, + void *data, size_t max_len ) { + struct dhcp_packet dhcppkt; + struct settings *settings; + int rc; + + /* Identify ProxyDHCP settings */ + settings = find_settings ( PROXYDHCP_SETTINGS_NAME ); + + /* No ProxyDHCP settings => return empty block */ + if ( ! settings ) { + memset ( data, 0, max_len ); + return 0; + } + + /* Create base DHCPACK packet */ + if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL, + data, max_len ) ) != 0 ) { + DBG ( "Could not create ProxyDHCPACK: %s\n", + strerror ( rc ) ); + return rc; + } + + /* Merge in ProxyDHCP options */ + if ( ( rc = copy_settings ( &dhcppkt, settings ) ) != 0 ) { + DBG ( "Could not set ProxyDHCPACK settings: %s\n", + strerror ( rc ) ); + return rc; + } + + return 0; +} diff --git a/src/net/ipv4.c b/src/net/ipv4.c index 67bfc2d6c..591293b7f 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -96,62 +96,6 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) { } /** - * Create IPv4 routing table - * - * @ret rc Return status code - */ -static int ipv4_create_routes ( void ) { - struct ipv4_miniroute *miniroute; - struct ipv4_miniroute *tmp; - struct net_device *netdev; - struct settings *settings; - struct in_addr address = { 0 }; - struct in_addr netmask = { 0 }; - struct in_addr gateway = { INADDR_NONE }; - - /* Delete all existing routes */ - list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list ) - del_ipv4_miniroute ( miniroute ); - - /* Create a route for each configured network device */ - for_each_netdev ( netdev ) { - settings = netdev_settings ( netdev ); - /* Get IPv4 address */ - address.s_addr = 0; - fetch_ipv4_setting ( settings, DHCP_EB_YIADDR, &address ); - if ( ! address.s_addr ) - continue; - /* Calculate default netmask */ - if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) { - netmask.s_addr = htonl ( IN_CLASSA_NET ); - } else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) { - netmask.s_addr = htonl ( IN_CLASSB_NET ); - } else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) { - netmask.s_addr = htonl ( IN_CLASSC_NET ); - } else { - netmask.s_addr = 0; - } - /* Override with subnet mask, if present */ - fetch_ipv4_setting ( settings, DHCP_SUBNET_MASK, &netmask ); - /* Get default gateway, if present */ - gateway.s_addr = INADDR_NONE; - fetch_ipv4_setting ( settings, DHCP_ROUTERS, &gateway ); - /* Configure route */ - miniroute = add_ipv4_miniroute ( netdev, address, - netmask, gateway ); - if ( ! miniroute ) - return -ENOMEM; - } - - return 0; -} - -/** IPv4 settings applicator */ -struct settings_applicator ipv4_settings_applicator __settings_applicator = { - .apply = ipv4_create_routes, -}; - -/** * Perform IPv4 routing * * @v dest Final destination address @@ -600,3 +544,90 @@ struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol = { .net_protocol = &ipv4_protocol, .check = ipv4_arp_check, }; + +/****************************************************************************** + * + * Settings + * + ****************************************************************************** + */ + +/** IPv4 address setting */ +struct setting ip_setting __setting = { + .name = "ip", + .description = "IPv4 address", + .tag = DHCP_EB_YIADDR, + .type = &setting_type_ipv4, +}; + +/** IPv4 subnet mask setting */ +struct setting netmask_setting __setting = { + .name = "netmask", + .description = "IPv4 subnet mask", + .tag = DHCP_SUBNET_MASK, + .type = &setting_type_ipv4, +}; + +/** Default gateway setting */ +struct setting gateway_setting __setting = { + .name = "gateway", + .description = "Default gateway", + .tag = DHCP_ROUTERS, + .type = &setting_type_ipv4, +}; + +/** + * Create IPv4 routing table based on configured settings + * + * @ret rc Return status code + */ +static int ipv4_create_routes ( void ) { + struct ipv4_miniroute *miniroute; + struct ipv4_miniroute *tmp; + struct net_device *netdev; + struct settings *settings; + struct in_addr address = { 0 }; + struct in_addr netmask = { 0 }; + struct in_addr gateway = { INADDR_NONE }; + + /* Delete all existing routes */ + list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list ) + del_ipv4_miniroute ( miniroute ); + + /* Create a route for each configured network device */ + for_each_netdev ( netdev ) { + settings = netdev_settings ( netdev ); + /* Get IPv4 address */ + address.s_addr = 0; + fetch_ipv4_setting ( settings, &ip_setting, &address ); + if ( ! address.s_addr ) + continue; + /* Calculate default netmask */ + if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) { + netmask.s_addr = htonl ( IN_CLASSA_NET ); + } else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) { + netmask.s_addr = htonl ( IN_CLASSB_NET ); + } else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) { + netmask.s_addr = htonl ( IN_CLASSC_NET ); + } else { + netmask.s_addr = 0; + } + /* Override with subnet mask, if present */ + fetch_ipv4_setting ( settings, &netmask_setting, &netmask ); + /* Get default gateway, if present */ + gateway.s_addr = INADDR_NONE; + fetch_ipv4_setting ( settings, &gateway_setting, &gateway ); + /* Configure route */ + miniroute = add_ipv4_miniroute ( netdev, address, + netmask, gateway ); + if ( ! miniroute ) + return -ENOMEM; + } + + return 0; +} + +/** IPv4 settings applicator */ +struct settings_applicator ipv4_settings_applicator __settings_applicator = { + .apply = ipv4_create_routes, +}; diff --git a/src/net/netdev_settings.c b/src/net/netdev_settings.c index c8e630a9c..44aca7d8a 100644 --- a/src/net/netdev_settings.c +++ b/src/net/netdev_settings.c @@ -28,28 +28,34 @@ * */ +/** Network device named settings */ +struct setting mac_setting __setting = { + .name = "mac", + .description = "MAC address", + .type = &setting_type_hex, +}; + /** * Store value of network device setting * * @v settings Settings block - * @v tag Setting tag number + * @v setting Setting to store * @v data Setting data, or NULL to clear setting * @v len Length of setting data * @ret rc Return status code */ -static int netdev_store ( struct settings *settings, unsigned int tag, +static int netdev_store ( struct settings *settings, struct setting *setting, const void *data, size_t len ) { struct net_device *netdev = container_of ( settings, struct net_device, settings.settings ); - switch ( tag ) { - case DHCP_EB_MAC: + if ( setting_cmp ( setting, &mac_setting ) == 0 ) { if ( len != netdev->ll_protocol->ll_addr_len ) return -EINVAL; memcpy ( netdev->ll_addr, data, len ); return 0; - default : - return simple_settings_store ( settings, tag, data, len ); + } else { + return simple_settings_store ( settings, setting, data, len ); } } @@ -57,24 +63,23 @@ static int netdev_store ( struct settings *settings, unsigned int tag, * Fetch value of network device setting * * @v settings Settings block - * @v tag Setting tag number + * @v setting Setting to fetch * @v data Setting data, or NULL to clear setting * @v len Length of setting data * @ret rc Return status code */ -static int netdev_fetch ( struct settings *settings, unsigned int tag, +static int netdev_fetch ( struct settings *settings, struct setting *setting, void *data, size_t len ) { struct net_device *netdev = container_of ( settings, struct net_device, settings.settings ); - switch ( tag ) { - case DHCP_EB_MAC: + if ( setting_cmp ( setting, &mac_setting ) == 0 ) { if ( len > netdev->ll_protocol->ll_addr_len ) len = netdev->ll_protocol->ll_addr_len; memcpy ( data, netdev->ll_addr, len ); return netdev->ll_protocol->ll_addr_len; - default : - return simple_settings_fetch ( settings, tag, data, len ); + } else { + return simple_settings_fetch ( settings, setting, data, len ); } } @@ -83,13 +88,3 @@ struct settings_operations netdev_settings_operations = { .store = netdev_store, .fetch = netdev_fetch, }; - -/** Network device named settings */ -struct named_setting netdev_named_settings[] __named_setting = { - { - .name = "mac", - .description = "MAC address", - .tag = DHCP_EB_MAC, - .type = &setting_type_hex, - }, -}; diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index f071b04a4..c01ca44b0 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -1591,14 +1591,22 @@ int iscsi_attach ( struct scsi_device *scsi, const char *root_path ) { /**************************************************************************** * - * Settings applicators + * Settings * */ +/** iSCSI initiator IQN setting */ +struct setting initiator_iqn_setting __setting = { + .name = "initiator-iqn", + .description = "iSCSI initiator name", + .tag = DHCP_ISCSI_INITIATOR_IQN, + .type = &setting_type_string, +}; + /** An iSCSI string setting */ struct iscsi_string_setting { - /** Setting tag number */ - unsigned int tag; + /** Setting */ + struct setting *setting; /** String to update */ char **string; /** String prefix */ @@ -1608,22 +1616,22 @@ struct iscsi_string_setting { /** iSCSI string settings */ static struct iscsi_string_setting iscsi_string_settings[] = { { - .tag = DHCP_ISCSI_INITIATOR_IQN, + .setting = &initiator_iqn_setting, .string = &iscsi_explicit_initiator_iqn, .prefix = "", }, { - .tag = DHCP_EB_USERNAME, + .setting = &username_setting, .string = &iscsi_username, .prefix = "", }, { - .tag = DHCP_EB_PASSWORD, + .setting = &password_setting, .string = &iscsi_password, .prefix = "", }, { - .tag = DHCP_HOST_NAME, + .setting = &hostname_setting, .string = &iscsi_default_initiator_iqn, .prefix = "iqn.2000-09.org.etherboot:", }, @@ -1648,7 +1656,7 @@ static int apply_iscsi_string_setting ( struct iscsi_string_setting *setting ){ /* Allocate new string */ prefix_len = strlen ( setting->prefix ); - setting_len = fetch_setting_len ( NULL, setting->tag ); + setting_len = fetch_setting_len ( NULL, setting->setting ); if ( setting_len < 0 ) { /* Missing settings are not errors; leave strings as NULL */ return 0; @@ -1660,7 +1668,7 @@ static int apply_iscsi_string_setting ( struct iscsi_string_setting *setting ){ /* Fill new string */ strcpy ( p, setting->prefix ); - check_len = fetch_string_setting ( NULL, setting->tag, + check_len = fetch_string_setting ( NULL, setting->setting, ( p + prefix_len ), ( len - prefix_len ) ); assert ( check_len == setting_len ); @@ -1682,8 +1690,8 @@ static int apply_iscsi_settings ( void ) { sizeof ( iscsi_string_settings[0] ) ) ; i++ ) { setting = &iscsi_string_settings[i]; if ( ( rc = apply_iscsi_string_setting ( setting ) ) != 0 ) { - DBG ( "iSCSI could not apply setting %d\n", - setting->tag ); + DBG ( "iSCSI could not apply setting %s\n", + setting->setting->name ); return rc; } } diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index 8789f9259..98b8af0ba 100644 --- a/src/net/udp/dhcp.c +++ b/src/net/udp/dhcp.c @@ -130,9 +130,6 @@ static uint32_t dhcp_xid ( struct net_device *netdev ) { return xid; } -/** Settings block name used for ProxyDHCP responses */ -#define PROXYDHCP_SETTINGS_NAME "proxydhcp" - /** * Create a DHCP packet * @@ -180,12 +177,12 @@ int create_dhcp_packet ( struct dhcp_packet *dhcppkt, memcpy ( dhcphdr->chaddr, netdev->ll_addr, hlen ); memcpy ( dhcphdr->options, options->data, options_len ); - /* Initialise DHCP packet structure and settings interface */ + /* Initialise DHCP packet structure */ memset ( dhcppkt, 0, sizeof ( *dhcppkt ) ); - dhcppkt_init ( dhcppkt, NULL, data, max_len ); + dhcppkt_init ( dhcppkt, data, max_len ); /* Set DHCP_MESSAGE_TYPE option */ - if ( ( rc = store_setting ( &dhcppkt->settings, DHCP_MESSAGE_TYPE, + if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype, sizeof ( msgtype ) ) ) != 0 ) return rc; @@ -230,10 +227,10 @@ struct dhcp_client_uuid { * @v max_len Size of DHCP packet buffer * @ret rc Return status code */ -static int create_dhcp_request ( struct dhcp_packet *dhcppkt, - struct net_device *netdev, - struct dhcp_packet *dhcpoffer, - void *data, size_t max_len ) { +int create_dhcp_request ( struct dhcp_packet *dhcppkt, + struct net_device *netdev, + struct dhcp_packet *dhcpoffer, + void *data, size_t max_len ) { struct device_description *desc = &netdev->dev->desc; struct dhcp_netdev_desc dhcp_desc; struct dhcp_client_id client_id; @@ -258,27 +255,26 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt, struct in_addr server_id; struct in_addr requested_ip; - if ( ( rc = fetch_ipv4_setting ( &dhcpoffer->settings, - DHCP_SERVER_IDENTIFIER, - &server_id ) ) < 0 ) { + if ( dhcppkt_fetch ( dhcpoffer, DHCP_SERVER_IDENTIFIER, + &server_id, sizeof ( server_id ) ) + != sizeof ( server_id ) ) { DBG ( "DHCP offer missing server identifier\n" ); return -EINVAL; } - if ( ( rc = fetch_ipv4_setting ( &dhcpoffer->settings, - DHCP_EB_YIADDR, - &requested_ip ) ) < 0 ) { + if ( dhcppkt_fetch ( dhcpoffer, DHCP_EB_YIADDR, + &requested_ip, sizeof ( requested_ip ) ) + != sizeof ( requested_ip ) ) { DBG ( "DHCP offer missing IP address\n" ); return -EINVAL; } - if ( ( rc = store_setting ( &dhcppkt->settings, - DHCP_SERVER_IDENTIFIER, &server_id, + if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER, + &server_id, sizeof ( server_id ) ) ) != 0 ) { DBG ( "DHCP could not set server identifier: %s\n ", strerror ( rc ) ); return rc; } - if ( ( rc = store_setting ( &dhcppkt->settings, - DHCP_REQUESTED_ADDRESS, + if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS, &requested_ip, sizeof ( requested_ip ) ) ) != 0 ){ DBG ( "DHCP could not set requested address: %s\n", @@ -289,8 +285,8 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt, /* Add options to identify the feature list */ dhcp_features_len = ( dhcp_features_end - dhcp_features ); - if ( ( rc = store_setting ( &dhcppkt->settings, DHCP_EB_ENCAP, - dhcp_features, dhcp_features_len ) ) !=0 ){ + if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_ENCAP, dhcp_features, + dhcp_features_len ) ) != 0 ) { DBG ( "DHCP could not set features list option: %s\n", strerror ( rc ) ); return rc; @@ -300,8 +296,8 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt, dhcp_desc.type = desc->bus_type; dhcp_desc.vendor = htons ( desc->vendor ); dhcp_desc.device = htons ( desc->device ); - if ( ( rc = store_setting ( &dhcppkt->settings, DHCP_EB_BUS_ID, - &dhcp_desc, sizeof ( dhcp_desc ) ) ) !=0 ){ + if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_BUS_ID, &dhcp_desc, + sizeof ( dhcp_desc ) ) ) != 0 ) { DBG ( "DHCP could not set bus ID option: %s\n", strerror ( rc ) ); return rc; @@ -314,8 +310,8 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt, ll_addr_len = netdev->ll_protocol->ll_addr_len; assert ( ll_addr_len <= sizeof ( client_id.ll_addr ) ); memcpy ( client_id.ll_addr, netdev->ll_addr, ll_addr_len ); - if ( ( rc = store_setting ( &dhcppkt->settings, DHCP_CLIENT_ID, - &client_id, ( ll_addr_len + 1 ) ) ) != 0 ){ + if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_ID, &client_id, + ( ll_addr_len + 1 ) ) ) != 0 ) { DBG ( "DHCP could not set client ID: %s\n", strerror ( rc ) ); return rc; @@ -324,8 +320,8 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt, /* Add client UUID, if we have one. Required for PXE. */ client_uuid.type = DHCP_CLIENT_UUID_TYPE; if ( ( rc = get_uuid ( &client_uuid.uuid ) ) == 0 ) { - if ( ( rc = store_setting ( &dhcppkt->settings, - DHCP_CLIENT_UUID, &client_uuid, + if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_UUID, + &client_uuid, sizeof ( client_uuid ) ) ) != 0 ) { DBG ( "DHCP could not set client UUID: %s\n", strerror ( rc ) ); @@ -336,169 +332,109 @@ static int create_dhcp_request ( struct dhcp_packet *dhcppkt, return 0; } -/** - * Create DHCPDISCOVER packet +/**************************************************************************** * - * @v netdev Network device - * @v data Buffer for DHCP packet - * @v max_len Size of DHCP packet buffer - * @ret rc Return status code + * DHCP settings * - * Used by external code. */ -int create_dhcpdiscover ( struct net_device *netdev, - void *data, size_t max_len ) { - struct dhcp_packet dhcppkt; - int rc; - if ( ( rc = create_dhcp_request ( &dhcppkt, netdev, NULL, data, - max_len ) ) != 0 ) { - DBG ( "Could not create DHCPDISCOVER: %s\n", - strerror ( rc ) ); - return rc; - } - - return 0; -} +/** A DHCP settings block */ +struct dhcp_settings { + /** Reference counter */ + struct refcnt refcnt; + /** Containing I/O buffer */ + struct io_buffer *iobuf; + /** DHCP packet */ + struct dhcp_packet dhcppkt; + /** Setting interface */ + struct settings settings; +}; /** - * Create DHCPACK packet + * Free DHCP settings block * - * @v netdev Network device - * @v data Buffer for DHCP packet - * @v max_len Size of DHCP packet buffer - * @ret rc Return status code - * - * Used by external code. + * @v refcnt Reference counter */ -int create_dhcpack ( struct net_device *netdev, - void *data, size_t max_len ) { - struct dhcp_packet dhcppkt; - int rc; - - /* Create base DHCPACK packet */ - if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL, - data, max_len ) ) != 0 ) { - DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) ); - return rc; - } - - /* Merge in globally-scoped settings, then netdev-specific - * settings. Do it in this order so that netdev-specific - * settings take precedence regardless of stated priorities. - */ - if ( ( rc = copy_settings ( &dhcppkt.settings, NULL ) ) != 0 ) { - DBG ( "Could not set DHCPACK global settings: %s\n", - strerror ( rc ) ); - return rc; - } - if ( ( rc = copy_settings ( &dhcppkt.settings, - netdev_settings ( netdev ) ) ) != 0 ) { - DBG ( "Could not set DHCPACK netdev settings: %s\n", - strerror ( rc ) ); - return rc; - } +static void dhcpset_free ( struct refcnt *refcnt ) { + struct dhcp_settings *dhcpset = + container_of ( refcnt, struct dhcp_settings, refcnt ); - return 0; + free_iob ( dhcpset->iobuf ); + free ( dhcpset ); } /** - * Create ProxyDHCPACK packet - * - * @v netdev Network device - * @v data Buffer for DHCP packet - * @v max_len Size of DHCP packet buffer - * @ret rc Return status code + * Decrement reference count on DHCP settings block * - * Used by external code. + * @v dhcpset DHCP settings block */ -int create_proxydhcpack ( struct net_device *netdev, - void *data, size_t max_len ) { - struct dhcp_packet dhcppkt; - struct settings *settings; - int rc; - - /* Identify ProxyDHCP settings */ - settings = find_settings ( PROXYDHCP_SETTINGS_NAME ); - - /* No ProxyDHCP settings => return empty block */ - if ( ! settings ) { - memset ( data, 0, max_len ); - return 0; - } - - /* Create base DHCPACK packet */ - if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL, - data, max_len ) ) != 0 ) { - DBG ( "Could not create ProxyDHCPACK: %s\n", - strerror ( rc ) ); - return rc; - } - - /* Merge in ProxyDHCP options */ - if ( ( rc = copy_settings ( &dhcppkt.settings, settings ) ) != 0 ) { - DBG ( "Could not set ProxyDHCPACK settings: %s\n", - strerror ( rc ) ); - return rc; - } - - return 0; +static inline void dhcpset_put ( struct dhcp_settings *dhcpset ) { + ref_put ( &dhcpset->refcnt ); } -/**************************************************************************** - * - * DHCP packets contained in I/O buffers +/** + * Store value of DHCP setting * + * @v settings Settings block + * @v setting Setting to store + * @v data Setting data, or NULL to clear setting + * @v len Length of setting data + * @ret rc Return status code */ +static int dhcpset_store ( struct settings *settings, struct setting *setting, + const void *data, size_t len ) { + struct dhcp_settings *dhcpset = + container_of ( settings, struct dhcp_settings, settings ); -/** A DHCP packet contained in an I/O buffer */ -struct dhcp_iobuf_packet { - /** DHCP packet */ - struct dhcp_packet dhcppkt; - /** Reference counter */ - struct refcnt refcnt; - /** Containing I/O buffer */ - struct io_buffer *iobuf; -}; + return dhcppkt_store ( &dhcpset->dhcppkt, setting->tag, data, len ); +} /** - * Free DHCP packet contained in an I/O buffer + * Fetch value of setting * - * @v refcnt Reference counter + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error */ -static void dhcpiob_free ( struct refcnt *refcnt ) { - struct dhcp_iobuf_packet *dhcpiob = - container_of ( refcnt, struct dhcp_iobuf_packet, refcnt ); +static int dhcpset_fetch ( struct settings *settings, struct setting *setting, + void *data, size_t len ) { + struct dhcp_settings *dhcpset = + container_of ( settings, struct dhcp_settings, settings ); - free_iob ( dhcpiob->iobuf ); - free ( dhcpiob ); + return dhcppkt_fetch ( &dhcpset->dhcppkt, setting->tag, data, len ); } +/** DHCP settings operations */ +static struct settings_operations dhcpset_settings_operations = { + .store = dhcpset_store, + .fetch = dhcpset_fetch, +}; + /** - * Create DHCP packet from I/O buffer + * Create DHCP setting block from I/O buffer * * @v iobuf I/O buffer - * @ret dhcpiob DHCP packet contained in I/O buffer + * @ret dhcpset DHCP settings block * * This function takes ownership of the I/O buffer. Future accesses - * must be via the @c dhcpiob data structure. + * must be via the @c dhcpset data structure. */ -static struct dhcp_iobuf_packet * dhcpiob_create ( struct io_buffer *iobuf ) { - struct dhcp_iobuf_packet *dhcpiob; - - dhcpiob = zalloc ( sizeof ( *dhcpiob ) ); - if ( dhcpiob ) { - dhcpiob->refcnt.free = dhcpiob_free; - dhcpiob->iobuf = iobuf; - dhcppkt_init ( &dhcpiob->dhcppkt, &dhcpiob->refcnt, +static struct dhcp_settings * dhcpset_create_iob ( struct io_buffer *iobuf ) { + struct dhcp_settings *dhcpset; + + dhcpset = zalloc ( sizeof ( *dhcpset ) ); + if ( dhcpset ) { + dhcpset->refcnt.free = dhcpset_free; + dhcpset->iobuf = iobuf; + dhcppkt_init ( &dhcpset->dhcppkt, iobuf->data, iob_len ( iobuf ) ); + settings_init ( &dhcpset->settings, + &dhcpset_settings_operations, &dhcpset->refcnt, + DHCP_SETTINGS_NAME ); } - return dhcpiob; -} - -static void dhcpiob_put ( struct dhcp_iobuf_packet *dhcpiob ) { - if ( dhcpiob ) - ref_put ( &dhcpiob->refcnt ); + return dhcpset; } /**************************************************************************** @@ -526,9 +462,9 @@ struct dhcp_session { */ int state; /** Response obtained from DHCP server */ - struct dhcp_iobuf_packet *response; + struct dhcp_settings *response; /** Response obtained from ProxyDHCP server */ - struct dhcp_iobuf_packet *proxy_response; + struct dhcp_settings *proxy_response; /** Retransmission timer */ struct retry_timer timer; /** Session start time (in ticks) */ @@ -545,8 +481,8 @@ static void dhcp_free ( struct refcnt *refcnt ) { container_of ( refcnt, struct dhcp_session, refcnt ); netdev_put ( dhcp->netdev ); - dhcpiob_put ( dhcp->response ); - dhcpiob_put ( dhcp->proxy_response ); + dhcpset_put ( dhcp->response ); + dhcpset_put ( dhcp->proxy_response ); free ( dhcp ); } @@ -584,7 +520,7 @@ static int dhcp_register_settings ( struct dhcp_session *dhcp ) { /* Register ProxyDHCP settings, if present */ if ( dhcp->proxy_response ) { - settings = &dhcp->proxy_response->dhcppkt.settings; + settings = &dhcp->proxy_response->settings; settings->name = PROXYDHCP_SETTINGS_NAME; old_settings = find_settings ( settings->name ); if ( old_settings ) @@ -595,7 +531,7 @@ static int dhcp_register_settings ( struct dhcp_session *dhcp ) { /* Register DHCP settings */ parent = netdev_settings ( dhcp->netdev ); - settings = &dhcp->response->dhcppkt.settings; + settings = &dhcp->response->settings; old_settings = find_child_settings ( parent, settings->name ); if ( old_settings ) unregister_settings ( old_settings ); @@ -701,24 +637,24 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer, struct xfer_metadata *meta __unused ) { struct dhcp_session *dhcp = container_of ( xfer, struct dhcp_session, xfer ); - struct dhcp_iobuf_packet *response; - struct dhcp_iobuf_packet **store_response; + struct dhcp_settings *response; + struct dhcp_settings **store_response; struct dhcphdr *dhcphdr; - struct settings *settings; - unsigned int msgtype; + uint8_t msgtype = 0; + uint8_t priority = 0; + uint8_t existing_priority = 0; unsigned long elapsed; int is_proxy; - int ignore_proxy; + uint8_t ignore_proxy = 0; int rc; /* Convert packet into a DHCP-packet-in-iobuf */ - response = dhcpiob_create ( iobuf ); + response = dhcpset_create_iob ( iobuf ); if ( ! response ) { DBGC ( dhcp, "DHCP %p could not store DHCP packet\n", dhcp ); return -ENOMEM; } dhcphdr = response->dhcppkt.dhcphdr; - settings = &response->dhcppkt.settings; /* Check for matching transaction ID */ if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) { @@ -730,7 +666,8 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer, /* Determine and verify message type */ is_proxy = ( dhcphdr->yiaddr.s_addr == 0 ); - msgtype = fetch_uintz_setting ( settings, DHCP_MESSAGE_TYPE ); + dhcppkt_fetch ( &response->dhcppkt, DHCP_MESSAGE_TYPE, &msgtype, + sizeof ( msgtype ) ); DBGC ( dhcp, "DHCP %p received %s%s\n", dhcp, ( is_proxy ? "Proxy" : "" ), dhcp_msgtype_name ( msgtype ) ); if ( ( ( dhcp->state != DHCPDISCOVER ) || ( msgtype != DHCPOFFER ) ) && @@ -746,14 +683,18 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer, * currently-stored options. */ store_response = ( is_proxy ? &dhcp->proxy_response : &dhcp->response); - if ( ( ! *store_response ) || - ( fetch_uintz_setting ( settings, DHCP_EB_PRIORITY ) >= - fetch_uintz_setting ( &(*store_response)->dhcppkt.settings, - DHCP_EB_PRIORITY ) ) ) { - dhcpiob_put ( *store_response ); + if ( *store_response ) { + dhcppkt_fetch ( &(*store_response)->dhcppkt, DHCP_EB_PRIORITY, + &existing_priority, + sizeof ( existing_priority ) ); + } + dhcppkt_fetch ( &response->dhcppkt, DHCP_EB_PRIORITY, &priority, + sizeof ( priority ) ); + if ( priority >= existing_priority ) { + dhcpset_put ( *store_response ); *store_response = response; } else { - dhcpiob_put ( response ); + dhcpset_put ( response ); } /* If we don't yet have a standard DHCP response (i.e. one @@ -763,8 +704,8 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer, goto out; /* Handle DHCP response */ - ignore_proxy = fetch_uintz_setting ( &dhcp->response->dhcppkt.settings, - DHCP_EB_NO_PROXYDHCP ); + dhcppkt_fetch ( &dhcp->response->dhcppkt, DHCP_EB_NO_PROXYDHCP, + &ignore_proxy, sizeof ( ignore_proxy ) ); switch ( dhcp->state ) { case DHCPDISCOVER: /* If we have allowed sufficient time for ProxyDHCP @@ -780,7 +721,7 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer, case DHCPREQUEST: /* DHCP finished; register options and exit */ if ( ignore_proxy && dhcp->proxy_response ) { - dhcpiob_put ( dhcp->proxy_response ); + dhcpset_put ( dhcp->proxy_response ); dhcp->proxy_response = NULL; } if ( ( rc = dhcp_register_settings ( dhcp ) ) != 0 ) { @@ -797,7 +738,7 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer, return 0; out_discard: - dhcpiob_put ( response ); + dhcpset_put ( response ); return 0; } diff --git a/src/net/udp/dns.c b/src/net/udp/dns.c index 5e632d180..1bcdbc7e4 100644 --- a/src/net/udp/dns.c +++ b/src/net/udp/dns.c @@ -506,6 +506,21 @@ struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = { .resolv = dns_resolv, }; +/****************************************************************************** + * + * Settings + * + ****************************************************************************** + */ + +/** DNS server setting */ +struct setting dns_setting __setting = { + .name = "dns", + .description = "DNS server", + .tag = DHCP_DNS_SERVERS, + .type = &setting_type_ipv4, +}; + /** * Apply nameserver setting * @@ -516,7 +531,7 @@ static int apply_nameserver_setting ( void ) { ( struct sockaddr_in * ) &nameserver; int len; - if ( ( len = fetch_ipv4_setting ( NULL, DHCP_DNS_SERVERS, + if ( ( len = fetch_ipv4_setting ( NULL, &dns_setting, &sin_nameserver->sin_addr ) ) >= 0 ){ sin_nameserver->sin_family = AF_INET; DBG ( "DNS using nameserver %s\n", diff --git a/src/net/udp/tftp.c b/src/net/udp/tftp.c index 8bd2b80b8..e49bcf9f7 100644 --- a/src/net/udp/tftp.c +++ b/src/net/udp/tftp.c @@ -1093,6 +1093,21 @@ struct uri_opener mtftp_uri_opener __uri_opener = { .open = mtftp_open, }; +/****************************************************************************** + * + * Settings + * + ****************************************************************************** + */ + +/** TFTP server setting */ +struct setting next_server_setting __setting = { + .name = "next-server", + .description = "TFTP server", + .tag = DHCP_EB_SIADDR, + .type = &setting_type_ipv4, +}; + /** * Apply TFTP configuration settings * @@ -1106,7 +1121,7 @@ static int tftp_apply_settings ( void ) { /* Retrieve TFTP server setting */ last_tftp_server = tftp_server; - fetch_ipv4_setting ( NULL, DHCP_EB_SIADDR, &tftp_server ); + fetch_ipv4_setting ( NULL, &next_server_setting, &tftp_server ); /* If TFTP server setting has changed, set the current working * URI to match. Do it only when the TFTP server has changed |