Skip to content

Commit 10d19bd

Browse files
committed
[pxe] Always retrieve cached DHCPACK and apply to relevant network device
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>
1 parent 1aa67eb commit 10d19bd

7 files changed

Lines changed: 239 additions & 198 deletions

File tree

src/arch/i386/core/cachedhcp.c

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License as
6+
* published by the Free Software Foundation; either version 2 of the
7+
* License, or any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful, but
10+
* WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17+
* 02110-1301, USA.
18+
*/
19+
20+
FILE_LICENCE ( GPL2_OR_LATER );
21+
22+
#include <stdint.h>
23+
#include <stdlib.h>
24+
#include <ipxe/dhcppkt.h>
25+
#include <ipxe/init.h>
26+
#include <ipxe/netdevice.h>
27+
#include <realmode.h>
28+
#include <pxe_api.h>
29+
30+
/** @file
31+
*
32+
* Cached DHCP packet
33+
*
34+
*/
35+
36+
/** Cached DHCPACK physical address
37+
*
38+
* This can be set by the prefix.
39+
*/
40+
uint32_t __bss16 ( cached_dhcpack_phys );
41+
#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys )
42+
43+
/** Colour for debug messages */
44+
#define colour &cached_dhcpack_phys
45+
46+
/** Cached DHCPACK */
47+
static struct dhcp_packet *cached_dhcpack;
48+
49+
/**
50+
* Cached DHCPACK startup function
51+
*
52+
*/
53+
static void cachedhcp_startup ( void ) {
54+
struct dhcp_packet *dhcppkt;
55+
struct dhcp_packet *tmp;
56+
struct dhcphdr *dhcphdr;
57+
size_t len;
58+
59+
/* Do nothing if no cached DHCPACK is present */
60+
if ( ! cached_dhcpack_phys ) {
61+
DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" );
62+
return;
63+
}
64+
65+
/* No reliable way to determine length before parsing packet;
66+
* start by assuming maximum length permitted by PXE.
67+
*/
68+
len = sizeof ( BOOTPLAYER_t );
69+
70+
/* Allocate and populate DHCP packet */
71+
dhcppkt = zalloc ( sizeof ( *dhcppkt ) + len );
72+
if ( ! dhcppkt ) {
73+
DBGC ( colour, "CACHEDHCP could not allocate copy\n" );
74+
return;
75+
}
76+
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
77+
copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0,
78+
len );
79+
dhcppkt_init ( dhcppkt, dhcphdr, len );
80+
81+
/* Resize packet to required length. If reallocation fails,
82+
* just continue to use the original packet.
83+
*/
84+
len = dhcppkt_len ( dhcppkt );
85+
tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) );
86+
if ( tmp )
87+
dhcppkt = tmp;
88+
89+
/* Reinitialise packet at new address */
90+
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
91+
dhcppkt_init ( dhcppkt, dhcphdr, len );
92+
93+
/* Store as cached DHCPACK, and mark original copy as consumed */
94+
DBGC ( colour, "CACHEDHCP found cached DHCPACK at %08x+%zx\n",
95+
cached_dhcpack_phys, len );
96+
cached_dhcpack = dhcppkt;
97+
cached_dhcpack_phys = 0;
98+
}
99+
100+
/**
101+
* Cached DHCPACK shutdown function
102+
*
103+
* @v booting Shutting down in order to boot
104+
*/
105+
static void cachedhcp_shutdown ( int booting __unused ) {
106+
107+
/* If cached DHCP packet has not yet been claimed, free it */
108+
if ( cached_dhcpack ) {
109+
DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" );
110+
dhcppkt_put ( cached_dhcpack );
111+
cached_dhcpack = NULL;
112+
}
113+
}
114+
115+
/** Cached DHCPACK initialisation function */
116+
struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
117+
.startup = cachedhcp_startup,
118+
.shutdown = cachedhcp_shutdown,
119+
};
120+
121+
/**
122+
* Apply cached DHCPACK to network device, if applicable
123+
*
124+
* @v netdev Network device
125+
* @ret rc Return status code
126+
*/
127+
static int cachedhcp_probe ( struct net_device *netdev ) {
128+
struct ll_protocol *ll_protocol = netdev->ll_protocol;
129+
int rc;
130+
131+
/* Do nothing unless we have a cached DHCPACK */
132+
if ( ! cached_dhcpack )
133+
return 0;
134+
135+
/* Do nothing unless cached DHCPACK's MAC address matches this
136+
* network device.
137+
*/
138+
if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr,
139+
ll_protocol->ll_addr_len ) != 0 ) {
140+
DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n",
141+
netdev->name );
142+
return 0;
143+
}
144+
DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name );
145+
146+
/* Register as DHCP settings for this network device */
147+
if ( ( rc = register_settings ( &cached_dhcpack->settings,
148+
netdev_settings ( netdev ),
149+
DHCP_SETTINGS_NAME ) ) != 0 ) {
150+
DBGC ( colour, "CACHEDHCP could not register settings: %s\n",
151+
strerror ( rc ) );
152+
return rc;
153+
}
154+
155+
/* Claim cached DHCPACK */
156+
dhcppkt_put ( cached_dhcpack );
157+
cached_dhcpack = NULL;
158+
159+
return 0;
160+
}
161+
162+
/**
163+
* Handle network device link state change
164+
*
165+
* @v netdev Network device
166+
*/
167+
static void cachedhcp_notify ( struct net_device *netdev __unused ) {
168+
169+
/* Nothing to do */
170+
}
171+
172+
/**
173+
* Handle network device removal
174+
*
175+
* @v netdev Network device
176+
*/
177+
static void cachedhcp_remove ( struct net_device *netdev __unused ) {
178+
179+
/* Nothing to do */
180+
}
181+
182+
/** Cached DHCP packet network device driver */
183+
struct net_driver cachedhcp_driver __net_driver = {
184+
.name = "cachedhcp",
185+
.probe = cachedhcp_probe,
186+
.notify = cachedhcp_notify,
187+
.remove = cachedhcp_remove,
188+
};

src/arch/i386/interface/pxeparent/pxeparent_dhcp.c

Lines changed: 0 additions & 70 deletions
This file was deleted.

src/arch/i386/prefix/pxeprefix.S

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ FILE_LICENCE ( GPL2_OR_LATER )
55
#define PXENV_UNDI_GET_IFACE_INFO 0x0013
66
#define PXENV_STOP_UNDI 0x0015
77
#define PXENV_UNLOAD_STACK 0x0070
8+
#define PXENV_GET_CACHED_INFO 0x0071
9+
#define PXENV_PACKET_TYPE_DHCP_ACK 0x0002
810
#define PXENV_FILE_CMDLINE 0x00e8
911

1012
#define PXE_HACK_EB54 0x0001
@@ -20,7 +22,18 @@ FILE_LICENCE ( GPL2_OR_LATER )
2022
#define EB_MAGIC_1 ( 'E' + ( 't' << 8 ) + ( 'h' << 16 ) + ( 'e' << 24 ) )
2123
#define EB_MAGIC_2 ( 'r' + ( 'b' << 8 ) + ( 'o' << 16 ) + ( 'o' << 24 ) )
2224

25+
/* Prefix memory layout:
26+
*
27+
* iPXE binary image
28+
* Temporary stack
29+
* Temporary copy of DHCPACK packet
30+
* Temporary copy of command line
31+
*/
2332
#define PREFIX_STACK_SIZE 2048
33+
#define PREFIX_TEMP_DHCPACK PREFIX_STACK_SIZE
34+
#define PREFIX_TEMP_DHCPACK_SIZE ( 1260 /* sizeof ( BOOTPLAYER_t ) */ )
35+
#define PREFIX_TEMP_CMDLINE ( PREFIX_TEMP_DHCPACK + PREFIX_TEMP_DHCPACK_SIZE )
36+
#define PREFIX_TEMP_CMDLINE_SIZE 4096
2437

2538
/*****************************************************************************
2639
* Entry point: set operating context, print welcome message
@@ -382,6 +395,32 @@ get_iface_type:
382395
99: movb $0x0a, %al
383396
call print_character
384397

398+
/*****************************************************************************
399+
* Get cached DHCP_ACK packet
400+
*****************************************************************************
401+
*/
402+
get_dhcpack:
403+
/* Issue PXENV_GET_CACHED_INFO */
404+
xorl %esi, %esi
405+
movw %ss, %si
406+
movw %si, ( pxe_parameter_structure + 0x08 )
407+
movw $PREFIX_TEMP_DHCPACK, ( pxe_parameter_structure + 0x06 )
408+
movw $PREFIX_TEMP_DHCPACK_SIZE, ( pxe_parameter_structure +0x04 )
409+
movw $PXENV_PACKET_TYPE_DHCP_ACK, ( pxe_parameter_structure + 0x02 )
410+
movw $PXENV_GET_CACHED_INFO, %bx
411+
call pxe_call
412+
jnc 1f
413+
call print_pxe_error
414+
jmp 99f
415+
1: /* Store physical address of packet */
416+
shll $4, %esi
417+
addl $PREFIX_TEMP_DHCPACK, %esi
418+
movl %esi, pxe_cached_dhcpack
419+
99:
420+
.section ".prefix.data", "aw", @progbits
421+
pxe_cached_dhcpack:
422+
.long 0
423+
.previous
385424

386425
/*****************************************************************************
387426
* Check for a command line
@@ -392,8 +431,8 @@ get_cmdline:
392431
xorl %esi, %esi
393432
movw %ss, %si
394433
movw %si, ( pxe_parameter_structure + 0x06 )
395-
movw $PREFIX_STACK_SIZE, ( pxe_parameter_structure + 0x04 )
396-
movw $0xffff, ( pxe_parameter_structure + 0x02 )
434+
movw $PREFIX_TEMP_CMDLINE, ( pxe_parameter_structure + 0x04 )
435+
movw $PREFIX_TEMP_CMDLINE_SIZE, ( pxe_parameter_structure + 0x02 )
397436
movw $PXENV_FILE_CMDLINE, %bx
398437
call pxe_call
399438
jc 99f /* Suppress errors; this is an iPXE extension API call */
@@ -403,7 +442,7 @@ get_cmdline:
403442
jz 99f
404443
/* Record command line */
405444
shll $4, %esi
406-
addl $PREFIX_STACK_SIZE, %esi
445+
addl $PREFIX_TEMP_CMDLINE, %esi
407446
movl %esi, pxe_cmdline
408447
99:
409448
.section ".prefix.data", "aw", @progbits
@@ -761,6 +800,9 @@ run_ipxe:
761800
/* Retrieve PXE command line, if any */
762801
movl pxe_cmdline, %esi
763802

803+
/* Retrieve cached DHCPACK, if any */
804+
movl pxe_cached_dhcpack, %ecx
805+
764806
/* Jump to .text16 segment with %ds pointing to .data16 */
765807
movw %bx, %ds
766808
pushw %ax
@@ -774,6 +816,9 @@ run_ipxe:
774816
/* Store command-line pointer */
775817
movl %esi, cmdline_phys
776818

819+
/* Store cached DHCPACK pointer */
820+
movl %ecx, cached_dhcpack_phys
821+
777822
/* Run main program */
778823
pushl $main
779824
pushw %cs

src/include/ipxe/dhcp.h

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -397,14 +397,7 @@ struct dhcp_netdev_desc {
397397
uint16_t device;
398398
} __attribute__ (( packed ));
399399

400-
/** Use cached network settings
401-
*
402-
* Cached network settings may be available from a prior DHCP request
403-
* (if running as a PXE NBP), non-volatile storage on the NIC, or
404-
* settings set via the command line or an embedded image. If this
405-
* flag is not set, it will be assumed that those sources are
406-
* insufficient and that DHCP should still be run when autobooting.
407-
*/
400+
/** Use cached network settings (obsolete; do not reuse this value) */
408401
#define DHCP_EB_USE_CACHED DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb2 )
409402

410403
/** BIOS drive number
@@ -677,12 +670,4 @@ extern int start_dhcp ( struct interface *job, struct net_device *netdev );
677670
extern int start_pxebs ( struct interface *job, struct net_device *netdev,
678671
unsigned int pxe_type );
679672

680-
/* In environments that can provide cached DHCP packets, this function
681-
* should look for such a packet and call store_cached_dhcpack() with
682-
* it if it exists.
683-
*/
684-
extern void get_cached_dhcpack ( void );
685-
686-
extern void store_cached_dhcpack ( userptr_t data, size_t len );
687-
688673
#endif /* _IPXE_DHCP_H */

0 commit comments

Comments
 (0)