diff options
author | Michael Brown <mcb30@ipxe.org> | 2015-08-29 16:49:54 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2015-08-29 16:58:12 +0100 |
commit | 2ef04f092c1449ba4cff631d5127455ddecc505f (patch) | |
tree | 8f3329c12b184b1a85da24aaa3d1b30e6411fff3 /src | |
parent | c522c11c7b7adedf0bf339b954e30951f02d568f (diff) | |
download | ipxe-2ef04f092c1449ba4cff631d5127455ddecc505f.tar.gz |
[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 <mcb30@ipxe.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/i386/image/pxe_image.c | 3 | ||||
-rw-r--r-- | src/arch/i386/include/pxe.h | 1 | ||||
-rw-r--r-- | 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 5b0f6eb89..297a618b8 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 66d752683..54649b504 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 6e09080bc..cc9c052ed 100644 --- a/src/arch/i386/interface/pxe/pxe_preboot.c +++ b/src/arch/i386/interface/pxe/pxe_preboot.c @@ -129,6 +129,38 @@ 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 * * @v None - @@ -149,12 +181,10 @@ 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 ), @@ -162,31 +192,15 @@ pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO *get_cached_info ) { 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 |