From 2ef04f092c1449ba4cff631d5127455ddecc505f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 29 Aug 2015 16:49:54 +0100 Subject: [PATCH] [pxe] Construct all fake DHCP packets before starting PXE NBP Commit edf74df ("[pxe] Always reconstruct packet for PXENV_GET_CACHED_INFO") fixed the problems caused by returning stale DHCP packets (e.g. from an earlier boot attempt using a different network device), but broke interoperability with NBPs such as WDS which may overwrite our cached (fake) DHCP packets and expect the modified packets to be returned by a subsequent call to PXENV_GET_CACHED_INFO. Fix by constructing the fake DHCP packets immediately before transferring control to a PXE NBP. Calls to PXENV_GET_CACHED_INFO will now never modify the cached packets. Signed-off-by: Michael Brown --- src/arch/i386/image/pxe_image.c | 3 ++ src/arch/i386/include/pxe.h | 1 + src/arch/i386/interface/pxe/pxe_preboot.c | 58 +++++++++++++---------- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/arch/i386/image/pxe_image.c b/src/arch/i386/image/pxe_image.c index 5b0f6eb8..297a618b 100644 --- a/src/arch/i386/image/pxe_image.c +++ b/src/arch/i386/image/pxe_image.c @@ -78,6 +78,9 @@ static int pxe_exec ( struct image *image ) { /* Activate PXE */ pxe_activate ( netdev ); + /* Construct fake DHCP packets */ + pxe_fake_cached_info(); + /* Set PXE command line */ pxe_cmdline = image->cmdline; diff --git a/src/arch/i386/include/pxe.h b/src/arch/i386/include/pxe.h index 66d75268..54649b50 100644 --- a/src/arch/i386/include/pxe.h +++ b/src/arch/i386/include/pxe.h @@ -192,6 +192,7 @@ extern struct net_device *pxe_netdev; extern const char *pxe_cmdline; extern void pxe_set_netdev ( struct net_device *netdev ); +extern void pxe_fake_cached_info ( void ); extern PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE *tftp_read_file ); extern PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader ); diff --git a/src/arch/i386/interface/pxe/pxe_preboot.c b/src/arch/i386/interface/pxe/pxe_preboot.c index 6e09080b..cc9c052e 100644 --- a/src/arch/i386/interface/pxe/pxe_preboot.c +++ b/src/arch/i386/interface/pxe/pxe_preboot.c @@ -128,6 +128,38 @@ pxenv_get_cached_info_name ( int packet_type ) { static union pxe_cached_info __bss16_array ( cached_info, [NUM_CACHED_INFOS] ); #define cached_info __use_data16 ( cached_info ) +/** + * Construct cached DHCP packets + * + */ +void pxe_fake_cached_info ( void ) { + struct pxe_dhcp_packet_creator *creator; + union pxe_cached_info *info; + unsigned int i; + int rc; + + /* Sanity check */ + assert ( pxe_netdev != NULL ); + + /* Erase any stale packets */ + memset ( cached_info, 0, sizeof ( cached_info ) ); + + /* Construct all DHCP packets */ + for ( i = 0 ; i < ( sizeof ( pxe_dhcp_packet_creators ) / + sizeof ( pxe_dhcp_packet_creators[0] ) ) ; i++ ) { + + /* Construct DHCP packet */ + creator = &pxe_dhcp_packet_creators[i]; + info = &cached_info[i]; + if ( ( rc = creator->create ( pxe_netdev, info, + sizeof ( *info ) ) ) != 0 ) { + DBGC ( &pxe_netdev, " failed to build packet: %s\n", + strerror ( rc ) ); + /* Continue constructing remaining packets */ + } + } +} + /** * UNLOAD BASE CODE STACK * @@ -149,44 +181,26 @@ pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) { */ static PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO *get_cached_info ) { - struct pxe_dhcp_packet_creator *creator; union pxe_cached_info *info; unsigned int idx; size_t len; userptr_t buffer; - int rc; DBGC ( &pxe_netdev, "PXENV_GET_CACHED_INFO %s to %04x:%04x+%x", pxenv_get_cached_info_name ( get_cached_info->PacketType ), get_cached_info->Buffer.segment, get_cached_info->Buffer.offset, get_cached_info->BufferSize ); - /* Sanity check */ - if ( ! pxe_netdev ) { - DBGC ( &pxe_netdev, "PXENV_GET_CACHED_INFO called with no " - "network device\n" ); - get_cached_info->Status = PXENV_STATUS_UNDI_INVALID_STATE; - return PXENV_EXIT_FAILURE; - } - /* Sanity check */ idx = ( get_cached_info->PacketType - 1 ); if ( idx >= NUM_CACHED_INFOS ) { DBGC ( &pxe_netdev, " bad PacketType %d\n", get_cached_info->PacketType ); - goto err; + get_cached_info->Status = PXENV_STATUS_UNSUPPORTED; + return PXENV_EXIT_FAILURE; } info = &cached_info[idx]; - /* Construct DHCP packet */ - creator = &pxe_dhcp_packet_creators[idx]; - if ( ( rc = creator->create ( pxe_netdev, info, - sizeof ( *info ) ) ) != 0 ) { - DBGC ( &pxe_netdev, " failed to build packet: %s\n", - strerror ( rc ) ); - goto err; - } - /* Copy packet (if applicable) */ len = get_cached_info->BufferSize; if ( len == 0 ) { @@ -238,10 +252,6 @@ pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO *get_cached_info ) { DBGC ( &pxe_netdev, "\n" ); get_cached_info->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; - - err: - get_cached_info->Status = PXENV_STATUS_OUT_OF_RESOURCES; - return PXENV_EXIT_FAILURE; } /* PXENV_RESTART_TFTP