summaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/net')
-rw-r--r--src/net/dhcpopts.c16
-rw-r--r--src/net/dhcppkt.c30
-rw-r--r--src/net/fakedhcp.c205
-rw-r--r--src/net/ipv4.c143
-rw-r--r--src/net/netdev_settings.c39
-rw-r--r--src/net/tcp/iscsi.c30
-rw-r--r--src/net/udp/dhcp.c303
-rw-r--r--src/net/udp/dns.c17
-rw-r--r--src/net/udp/tftp.c17
9 files changed, 503 insertions, 297 deletions
diff --git a/src/net/dhcpopts.c b/src/net/dhcpopts.c
index 64b310d4..1898011a 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 0a11520f..1cf99d8d 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 00000000..c3054db1
--- /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 67bfc2d6..591293b7 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 c8e630a9..44aca7d8 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 f071b04a..c01ca44b 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 8789f925..98b8af0b 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 5e632d18..1bcdbc7e 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 8bd2b80b..e49bcf9f 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