diff options
Diffstat (limited to 'src/arch')
| -rw-r--r-- | src/arch/i386/core/cachedhcp.c | 188 | ||||
| -rw-r--r-- | src/arch/i386/interface/pxeparent/pxeparent_dhcp.c | 70 | ||||
| -rw-r--r-- | src/arch/i386/prefix/pxeprefix.S | 51 |
3 files changed, 236 insertions, 73 deletions
diff --git a/src/arch/i386/core/cachedhcp.c b/src/arch/i386/core/cachedhcp.c new file mode 100644 index 000000000..9ebde3e8c --- /dev/null +++ b/src/arch/i386/core/cachedhcp.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdlib.h> +#include <ipxe/dhcppkt.h> +#include <ipxe/init.h> +#include <ipxe/netdevice.h> +#include <realmode.h> +#include <pxe_api.h> + +/** @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 f37286335..000000000 --- a/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2009 Joshua Oreman <oremanj@rwcr.net>. - * - * 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 <string.h> -#include <ipxe/dhcp.h> -#include <ipxe/netdevice.h> -#include <undipreload.h> -#include <pxeparent.h> -#include <realmode.h> -#include <pxe_api.h> - -/** - * 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 05db9894c..6e29c7949 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 |
