diff --git a/src/arch/i386/core/cachedhcp.c b/src/arch/i386/core/cachedhcp.c new file mode 100644 index 00000000..9ebde3e8 --- /dev/null +++ b/src/arch/i386/core/cachedhcp.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2013 Michael Brown . + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Cached DHCP packet + * + */ + +/** Cached DHCPACK physical address + * + * This can be set by the prefix. + */ +uint32_t __bss16 ( cached_dhcpack_phys ); +#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys ) + +/** Colour for debug messages */ +#define colour &cached_dhcpack_phys + +/** Cached DHCPACK */ +static struct dhcp_packet *cached_dhcpack; + +/** + * Cached DHCPACK startup function + * + */ +static void cachedhcp_startup ( void ) { + struct dhcp_packet *dhcppkt; + struct dhcp_packet *tmp; + struct dhcphdr *dhcphdr; + size_t len; + + /* Do nothing if no cached DHCPACK is present */ + if ( ! cached_dhcpack_phys ) { + DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" ); + return; + } + + /* No reliable way to determine length before parsing packet; + * start by assuming maximum length permitted by PXE. + */ + len = sizeof ( BOOTPLAYER_t ); + + /* Allocate and populate DHCP packet */ + dhcppkt = zalloc ( sizeof ( *dhcppkt ) + len ); + if ( ! dhcppkt ) { + DBGC ( colour, "CACHEDHCP could not allocate copy\n" ); + return; + } + dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); + copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0, + len ); + dhcppkt_init ( dhcppkt, dhcphdr, len ); + + /* Resize packet to required length. If reallocation fails, + * just continue to use the original packet. + */ + len = dhcppkt_len ( dhcppkt ); + tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) ); + if ( tmp ) + dhcppkt = tmp; + + /* Reinitialise packet at new address */ + dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); + dhcppkt_init ( dhcppkt, dhcphdr, len ); + + /* Store as cached DHCPACK, and mark original copy as consumed */ + DBGC ( colour, "CACHEDHCP found cached DHCPACK at %08x+%zx\n", + cached_dhcpack_phys, len ); + cached_dhcpack = dhcppkt; + cached_dhcpack_phys = 0; +} + +/** + * Cached DHCPACK shutdown function + * + * @v booting Shutting down in order to boot + */ +static void cachedhcp_shutdown ( int booting __unused ) { + + /* If cached DHCP packet has not yet been claimed, free it */ + if ( cached_dhcpack ) { + DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" ); + dhcppkt_put ( cached_dhcpack ); + cached_dhcpack = NULL; + } +} + +/** Cached DHCPACK initialisation function */ +struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_NORMAL ) = { + .startup = cachedhcp_startup, + .shutdown = cachedhcp_shutdown, +}; + +/** + * Apply cached DHCPACK to network device, if applicable + * + * @v netdev Network device + * @ret rc Return status code + */ +static int cachedhcp_probe ( struct net_device *netdev ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; + int rc; + + /* Do nothing unless we have a cached DHCPACK */ + if ( ! cached_dhcpack ) + return 0; + + /* Do nothing unless cached DHCPACK's MAC address matches this + * network device. + */ + if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr, + ll_protocol->ll_addr_len ) != 0 ) { + DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n", + netdev->name ); + return 0; + } + DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name ); + + /* Register as DHCP settings for this network device */ + if ( ( rc = register_settings ( &cached_dhcpack->settings, + netdev_settings ( netdev ), + DHCP_SETTINGS_NAME ) ) != 0 ) { + DBGC ( colour, "CACHEDHCP could not register settings: %s\n", + strerror ( rc ) ); + return rc; + } + + /* Claim cached DHCPACK */ + dhcppkt_put ( cached_dhcpack ); + cached_dhcpack = NULL; + + return 0; +} + +/** + * Handle network device link state change + * + * @v netdev Network device + */ +static void cachedhcp_notify ( struct net_device *netdev __unused ) { + + /* Nothing to do */ +} + +/** + * Handle network device removal + * + * @v netdev Network device + */ +static void cachedhcp_remove ( struct net_device *netdev __unused ) { + + /* Nothing to do */ +} + +/** Cached DHCP packet network device driver */ +struct net_driver cachedhcp_driver __net_driver = { + .name = "cachedhcp", + .probe = cachedhcp_probe, + .notify = cachedhcp_notify, + .remove = cachedhcp_remove, +}; diff --git a/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c b/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c deleted file mode 100644 index f3728633..00000000 --- a/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2009 Joshua Oreman . - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include -#include -#include -#include -#include -#include -#include - -/** - * Present cached DHCP packet if it exists - */ -void get_cached_dhcpack ( void ) { - struct undi_device *undi; - struct s_PXENV_GET_CACHED_INFO get_cached_info; - int rc; - - /* Use preloaded UNDI device to get at PXE entry point */ - undi = &preloaded_undi; - if ( ! undi->entry.segment ) { - DBG ( "PXEDHCP no preloaded UNDI device found\n" ); - return; - } - - /* Check that stack is available to get cached info */ - if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) { - DBG ( "PXEDHCP stack was unloaded, no cache available\n" ); - return; - } - - /* Obtain cached DHCP packet */ - memset ( &get_cached_info, 0, sizeof ( get_cached_info ) ); - get_cached_info.PacketType = PXENV_PACKET_TYPE_DHCP_ACK; - - if ( ( rc = pxeparent_call ( undi->entry, PXENV_GET_CACHED_INFO, - &get_cached_info, - sizeof ( get_cached_info ) ) ) != 0 ) { - DBG ( "PXEDHCP GET_CACHED_INFO failed: %s\n", strerror ( rc ) ); - return; - } - - DBG ( "PXEDHCP got cached info at %04x:%04x length %d\n", - get_cached_info.Buffer.segment, get_cached_info.Buffer.offset, - get_cached_info.BufferSize ); - - /* Present cached DHCP packet */ - store_cached_dhcpack ( real_to_user ( get_cached_info.Buffer.segment, - get_cached_info.Buffer.offset ), - get_cached_info.BufferSize ); -} diff --git a/src/arch/i386/prefix/pxeprefix.S b/src/arch/i386/prefix/pxeprefix.S index 05db9894..6e29c794 100644 --- a/src/arch/i386/prefix/pxeprefix.S +++ b/src/arch/i386/prefix/pxeprefix.S @@ -5,6 +5,8 @@ FILE_LICENCE ( GPL2_OR_LATER ) #define PXENV_UNDI_GET_IFACE_INFO 0x0013 #define PXENV_STOP_UNDI 0x0015 #define PXENV_UNLOAD_STACK 0x0070 +#define PXENV_GET_CACHED_INFO 0x0071 +#define PXENV_PACKET_TYPE_DHCP_ACK 0x0002 #define PXENV_FILE_CMDLINE 0x00e8 #define PXE_HACK_EB54 0x0001 @@ -20,7 +22,18 @@ FILE_LICENCE ( GPL2_OR_LATER ) #define EB_MAGIC_1 ( 'E' + ( 't' << 8 ) + ( 'h' << 16 ) + ( 'e' << 24 ) ) #define EB_MAGIC_2 ( 'r' + ( 'b' << 8 ) + ( 'o' << 16 ) + ( 'o' << 24 ) ) +/* Prefix memory layout: + * + * iPXE binary image + * Temporary stack + * Temporary copy of DHCPACK packet + * Temporary copy of command line + */ #define PREFIX_STACK_SIZE 2048 +#define PREFIX_TEMP_DHCPACK PREFIX_STACK_SIZE +#define PREFIX_TEMP_DHCPACK_SIZE ( 1260 /* sizeof ( BOOTPLAYER_t ) */ ) +#define PREFIX_TEMP_CMDLINE ( PREFIX_TEMP_DHCPACK + PREFIX_TEMP_DHCPACK_SIZE ) +#define PREFIX_TEMP_CMDLINE_SIZE 4096 /***************************************************************************** * Entry point: set operating context, print welcome message @@ -382,6 +395,32 @@ get_iface_type: 99: movb $0x0a, %al call print_character +/***************************************************************************** + * Get cached DHCP_ACK packet + ***************************************************************************** + */ +get_dhcpack: + /* Issue PXENV_GET_CACHED_INFO */ + xorl %esi, %esi + movw %ss, %si + movw %si, ( pxe_parameter_structure + 0x08 ) + movw $PREFIX_TEMP_DHCPACK, ( pxe_parameter_structure + 0x06 ) + movw $PREFIX_TEMP_DHCPACK_SIZE, ( pxe_parameter_structure +0x04 ) + movw $PXENV_PACKET_TYPE_DHCP_ACK, ( pxe_parameter_structure + 0x02 ) + movw $PXENV_GET_CACHED_INFO, %bx + call pxe_call + jnc 1f + call print_pxe_error + jmp 99f +1: /* Store physical address of packet */ + shll $4, %esi + addl $PREFIX_TEMP_DHCPACK, %esi + movl %esi, pxe_cached_dhcpack +99: + .section ".prefix.data", "aw", @progbits +pxe_cached_dhcpack: + .long 0 + .previous /***************************************************************************** * Check for a command line @@ -392,8 +431,8 @@ get_cmdline: xorl %esi, %esi movw %ss, %si movw %si, ( pxe_parameter_structure + 0x06 ) - movw $PREFIX_STACK_SIZE, ( pxe_parameter_structure + 0x04 ) - movw $0xffff, ( pxe_parameter_structure + 0x02 ) + movw $PREFIX_TEMP_CMDLINE, ( pxe_parameter_structure + 0x04 ) + movw $PREFIX_TEMP_CMDLINE_SIZE, ( pxe_parameter_structure + 0x02 ) movw $PXENV_FILE_CMDLINE, %bx call pxe_call jc 99f /* Suppress errors; this is an iPXE extension API call */ @@ -403,7 +442,7 @@ get_cmdline: jz 99f /* Record command line */ shll $4, %esi - addl $PREFIX_STACK_SIZE, %esi + addl $PREFIX_TEMP_CMDLINE, %esi movl %esi, pxe_cmdline 99: .section ".prefix.data", "aw", @progbits @@ -761,6 +800,9 @@ run_ipxe: /* Retrieve PXE command line, if any */ movl pxe_cmdline, %esi + /* Retrieve cached DHCPACK, if any */ + movl pxe_cached_dhcpack, %ecx + /* Jump to .text16 segment with %ds pointing to .data16 */ movw %bx, %ds pushw %ax @@ -774,6 +816,9 @@ run_ipxe: /* Store command-line pointer */ movl %esi, cmdline_phys + /* Store cached DHCPACK pointer */ + movl %ecx, cached_dhcpack_phys + /* Run main program */ pushl $main pushw %cs diff --git a/src/include/ipxe/dhcp.h b/src/include/ipxe/dhcp.h index 6c028466..2429fae0 100644 --- a/src/include/ipxe/dhcp.h +++ b/src/include/ipxe/dhcp.h @@ -397,14 +397,7 @@ struct dhcp_netdev_desc { uint16_t device; } __attribute__ (( packed )); -/** Use cached network settings - * - * Cached network settings may be available from a prior DHCP request - * (if running as a PXE NBP), non-volatile storage on the NIC, or - * settings set via the command line or an embedded image. If this - * flag is not set, it will be assumed that those sources are - * insufficient and that DHCP should still be run when autobooting. - */ +/** Use cached network settings (obsolete; do not reuse this value) */ #define DHCP_EB_USE_CACHED DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb2 ) /** BIOS drive number @@ -677,12 +670,4 @@ extern int start_dhcp ( struct interface *job, struct net_device *netdev ); extern int start_pxebs ( struct interface *job, struct net_device *netdev, unsigned int pxe_type ); -/* In environments that can provide cached DHCP packets, this function - * should look for such a packet and call store_cached_dhcpack() with - * it if it exists. - */ -extern void get_cached_dhcpack ( void ); - -extern void store_cached_dhcpack ( userptr_t data, size_t len ); - #endif /* _IPXE_DHCP_H */ diff --git a/src/net/cachedhcp.c b/src/net/cachedhcp.c deleted file mode 100644 index fc7dabc9..00000000 --- a/src/net/cachedhcp.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2009 Joshua Oreman . - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include -#include -#include -#include -#include -#include -#include -#include - -/** @file - * - * Cached DHCP packet handling - * - */ - -/** - * Store cached DHCPACK packet - * - * @v data User pointer to cached DHCP packet data - * @v len Length of cached DHCP packet data - * @ret rc Return status code - * - * This function should be called by the architecture-specific - * get_cached_dhcpack() handler. - */ -void store_cached_dhcpack ( userptr_t data, size_t len ) { - struct dhcp_packet *dhcppkt; - struct dhcphdr *dhcphdr; - struct settings *parent; - int rc; - - /* Create DHCP packet */ - dhcppkt = zalloc ( sizeof ( *dhcppkt ) + len ); - if ( ! dhcppkt ) - return; - - /* Fill in data for DHCP packet */ - dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( * dhcppkt ) ); - copy_from_user ( dhcphdr, data, 0, len ); - dhcppkt_init ( dhcppkt, dhcphdr, len ); - DBG_HD ( dhcppkt->options.data, dhcppkt->options.used_len ); - - /* Register settings on the last opened network device. - * This will have the effect of registering cached settings - * with a network device when "dhcp netX" is performed for that - * device, which is usually what we want. - */ - parent = netdev_settings ( last_opened_netdev() ); - if ( ( rc = register_settings ( &dhcppkt->settings, parent, - DHCP_SETTINGS_NAME ) ) != 0 ) - DBG ( "DHCP could not register cached settings: %s\n", - strerror ( rc ) ); - - dhcppkt_put ( dhcppkt ); - - DBG ( "DHCP registered cached settings\n" ); -} diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index 762ae732..be03096b 100644 --- a/src/net/udp/dhcp.c +++ b/src/net/udp/dhcp.c @@ -107,14 +107,6 @@ struct setting user_class_setting __setting ( SETTING_HOST_EXTRA ) = { .type = &setting_type_string, }; -/** Use cached network settings */ -struct setting use_cached_setting __setting ( SETTING_MISC ) = { - .name = "use-cached", - .description = "Use cached settings", - .tag = DHCP_EB_USE_CACHED, - .type = &setting_type_uint8, -}; - /** * Most recent DHCP transaction ID * @@ -1284,38 +1276,21 @@ static struct sockaddr dhcp_peer = { .sa_family = AF_INET, }; -/** - * Get cached DHCPACK where none exists - */ -__weak void get_cached_dhcpack ( void ) { __keepme } - /** * Start DHCP state machine on a network device * * @v job Job control interface * @v netdev Network device - * @ret rc Return status code, or positive if cached + * @ret rc Return status code * * Starts DHCP on the specified network device. If successful, the * DHCPACK (and ProxyDHCPACK, if applicable) will be registered as * option sources. - * - * On a return of 0, a background job has been started to perform the - * DHCP request. Any nonzero return means the job has not been - * started; a positive return value indicates the success condition of - * having fetched the appropriate data from cached information. */ int start_dhcp ( struct interface *job, struct net_device *netdev ) { struct dhcp_session *dhcp; int rc; - /* Check for cached DHCP information */ - get_cached_dhcpack(); - if ( fetch_uintz_setting ( NULL, &use_cached_setting ) ) { - DBG ( "DHCP using cached network settings\n" ); - return 1; - } - /* Allocate and initialise structure */ dhcp = zalloc ( sizeof ( *dhcp ) ); if ( ! dhcp ) diff --git a/src/usr/dhcpmgmt.c b/src/usr/dhcpmgmt.c index b61c01aa..10d8ecfa 100644 --- a/src/usr/dhcpmgmt.c +++ b/src/usr/dhcpmgmt.c @@ -51,12 +51,8 @@ int dhcp ( struct net_device *netdev ) { /* Perform DHCP */ printf ( "DHCP (%s %s)", netdev->name, netdev->ll_protocol->ntoa ( netdev->ll_addr ) ); - if ( ( rc = start_dhcp ( &monojob, netdev ) ) == 0 ) { + if ( ( rc = start_dhcp ( &monojob, netdev ) ) == 0 ) rc = monojob_wait ( "" ); - } else if ( rc > 0 ) { - printf ( " using cached\n" ); - rc = 0; - } return rc; }