]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[pxe] Always retrieve cached DHCPACK and apply to relevant network device
authorMichael Brown <mcb30@ipxe.org>
Fri, 25 Oct 2013 16:24:09 +0000 (17:24 +0100)
committerMichael Brown <mcb30@ipxe.org>
Fri, 25 Oct 2013 16:29:25 +0000 (17:29 +0100)
When chainloading, always retrieve the cached DHCPACK packet from the
underlying PXE stack, and apply it as the original contents of the
"net<X>.dhcp" settings block.  This allows cached DHCP settings to be
used for any chainloaded iPXE binary (not just undionly.kkpxe).

This change eliminates the undocumented "use-cached" setting.  Issuing
the "dhcp" command will now always result in a fresh DHCP request.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/i386/core/cachedhcp.c [new file with mode: 0644]
src/arch/i386/interface/pxeparent/pxeparent_dhcp.c [deleted file]
src/arch/i386/prefix/pxeprefix.S
src/include/ipxe/dhcp.h
src/net/cachedhcp.c [deleted file]
src/net/udp/dhcp.c
src/usr/dhcpmgmt.c

diff --git a/src/arch/i386/core/cachedhcp.c b/src/arch/i386/core/cachedhcp.c
new file mode 100644 (file)
index 0000000..9ebde3e
--- /dev/null
@@ -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 (file)
index f372863..0000000
+++ /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 );
-}
index 05db9894cc00b57f9c9b5d51747f61cc9b75609c..6e29c794929b097b10289179e5a1dbaa9dcf5bc6 100644 (file)
@@ -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
index 6c028466c7d874143fb114ef37a0d4e8423db293..2429fae02816144a4b5c5c797eb6c48eafaff8a5 100644 (file)
@@ -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 (file)
index fc7dabc..0000000
+++ /dev/null
@@ -1,78 +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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ipxe/dhcp.h>
-#include <ipxe/dhcppkt.h>
-#include <ipxe/netdevice.h>
-#include <ipxe/iobuf.h>
-#include <ipxe/uaccess.h>
-
-/** @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" );
-}
index 762ae732aa3a1992e6a106bb758ca52ce1009634..be03096b6fae3fb91e84172d6664f533ecf44ee4 100644 (file)
@@ -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 )
index b61c01aa30d4d318ac842853947e7805278c0410..10d8ecfa595067017af48285fd24369c3b3dbfc8 100644 (file)
@@ -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;
 }