Skip to content

Commit

Permalink
[pxe] Construct all fake DHCP packets before starting PXE NBP
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mcb30 committed Aug 29, 2015
1 parent c522c11 commit 2ef04f0
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 24 deletions.
3 changes: 3 additions & 0 deletions src/arch/i386/image/pxe_image.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions src/arch/i386/include/pxe.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down
58 changes: 34 additions & 24 deletions src/arch/i386/interface/pxe/pxe_preboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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 ) {
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 2ef04f0

Please sign in to comment.