Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[dhcp] Split PXE menuing code out of dhcp.c
The DHCP client code now implements only the mechanism of the DHCP and
PXE Boot Server protocols.  Boot Server Discovery can be initiated
manually using the "pxebs" command.  The menuing code is separated out
into a user-level function on a par with boot_root_path(), and is
entered in preference to a normal filename boot if the DHCP vendor
class is "PXEClient" and the PXE boot menu option exists.
  • Loading branch information
Michael Brown committed Feb 1, 2009
1 parent d2b0081 commit e65afc4
Show file tree
Hide file tree
Showing 17 changed files with 1,367 additions and 961 deletions.
2 changes: 1 addition & 1 deletion src/arch/i386/interface/pxe/pxe_preboot.c
Expand Up @@ -82,7 +82,7 @@ struct pxe_dhcp_packet_creator {
static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = {
[CACHED_INFO_DHCPDISCOVER] = { create_fakedhcpdiscover },
[CACHED_INFO_DHCPACK] = { create_fakedhcpack },
[CACHED_INFO_BINL] = { create_fakeproxydhcpack },
[CACHED_INFO_BINL] = { create_fakepxebsack },
};

/* The case in which the caller doesn't supply a buffer is really
Expand Down
99 changes: 94 additions & 5 deletions src/hci/commands/dhcp_cmd.c
Expand Up @@ -26,6 +26,7 @@
#include <assert.h>
#include <getopt.h>
#include <gpxe/netdevice.h>
#include <gpxe/in.h>
#include <gpxe/command.h>
#include <usr/dhcpmgmt.h>

Expand Down Expand Up @@ -60,7 +61,7 @@ static int dhcp_exec ( int argc, char **argv ) {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
const char *name;
const char *netdev_txt;
struct net_device *netdev;
int c;
int rc;
Expand All @@ -82,14 +83,16 @@ static int dhcp_exec ( int argc, char **argv ) {
dhcp_syntax ( argv );
return 1;
}
name = argv[optind];
netdev_txt = argv[optind];

/* Perform DHCP */
netdev = find_netdev ( name );
/* Parse arguments */
netdev = find_netdev ( netdev_txt );
if ( ! netdev ) {
printf ( "No such interface: %s\n", name );
printf ( "No such interface: %s\n", netdev_txt );
return 1;
}

/* Perform DHCP */
if ( ( rc = dhcp ( netdev ) ) != 0 ) {
printf ( "Could not configure %s: %s\n", netdev->name,
strerror ( rc ) );
Expand All @@ -99,10 +102,96 @@ static int dhcp_exec ( int argc, char **argv ) {
return 0;
}

/**
* "pxebs" command syntax message
*
* @v argv Argument list
*/
static void pxebs_syntax ( char **argv ) {
printf ( "Usage:\n"
" %s <interface> <discovery_ip> <server_type>\n"
"\n"
"Perform PXE Boot Server discovery\n",
argv[0] );
}

/**
* The "pxebs" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Exit code
*/
static int pxebs_exec ( int argc, char **argv ) {
static struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
const char *netdev_txt;
const char *pxe_server_txt;
const char *pxe_type_txt;
struct net_device *netdev;
struct in_addr pxe_server;
unsigned int pxe_type;
char *end;
int c;
int rc;

/* Parse options */
while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
switch ( c ) {
case 'h':
/* Display help text */
default:
/* Unrecognised/invalid option */
pxebs_syntax ( argv );
return 1;
}
}

/* Need exactly one interface name remaining after the options */
if ( optind != ( argc - 3 ) ) {
pxebs_syntax ( argv );
return 1;
}
netdev_txt = argv[optind];
pxe_server_txt = argv[ optind + 1 ];
pxe_type_txt = argv[ optind + 2 ];

/* Parse arguments */
netdev = find_netdev ( netdev_txt );
if ( ! netdev ) {
printf ( "No such interface: %s\n", netdev_txt );
return 1;
}
if ( inet_aton ( pxe_server_txt, &pxe_server ) == 0 ) {
printf ( "Bad discovery IP address: %s\n", pxe_server_txt );
return 1;
}
pxe_type = strtoul ( pxe_type_txt, &end, 0 );
if ( *end ) {
printf ( "Bad server type: %s\n", pxe_type_txt );
return 1;
}

/* Perform Boot Server Discovery */
if ( ( rc = pxebs ( netdev, pxe_server, pxe_type ) ) != 0 ) {
printf ( "Could not discover boot server on %s: %s\n",
netdev->name, strerror ( rc ) );
return 1;
}

return 0;
}

/** DHCP management commands */
struct command dhcp_commands[] __command = {
{
.name = "dhcp",
.exec = dhcp_exec,
},
{
.name = "pxebs",
.exec = pxebs_exec,
},
};
2 changes: 1 addition & 1 deletion src/hci/mucurses/ansi_screen.c
Expand Up @@ -15,7 +15,7 @@ static void ansiscr_reset ( struct _curses_screen *scr ) {
scr->attrs = 0;
scr->curs_x = 0;
scr->curs_y = 0;
printf ( "\033[0m\033[2J\033[1;1H" );
printf ( "\033[0m" );
}

static void ansiscr_movetoyx ( struct _curses_screen *scr,
Expand Down
4 changes: 2 additions & 2 deletions src/hci/mucurses/wininit.c
Expand Up @@ -18,7 +18,7 @@ WINDOW *initscr ( void ) {
stdscr->scr->init( stdscr->scr );
stdscr->height = LINES;
stdscr->width = COLS;
erase();
move ( 0, 0 );
return stdscr;
}

Expand All @@ -29,7 +29,7 @@ WINDOW *initscr ( void ) {
int endwin ( void ) {
attrset ( 0 );
color_set ( 0, NULL );
erase();
mvprintw ( ( LINES - 1 ), 0, "\n" );
stdscr->scr->exit( stdscr->scr );
return OK;
}
90 changes: 79 additions & 11 deletions src/include/gpxe/dhcp.h
Expand Up @@ -12,12 +12,12 @@
#include <gpxe/list.h>
#include <gpxe/refcnt.h>
#include <gpxe/tables.h>
#include <gpxe/uuid.h>
#include <gpxe/netdevice.h>

struct net_device;
struct job_interface;
struct dhcp_options;
struct dhcp_packet;
struct dhcp_pxe_boot_menu_item;

/** BOOTP/DHCP server port */
#define BOOTPS_PORT 67
Expand Down Expand Up @@ -88,12 +88,53 @@ struct dhcp_pxe_boot_menu_item;
/** PXE boot menu */
#define DHCP_PXE_BOOT_MENU DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 9 )

/** PXE boot menu */
struct dhcp_pxe_boot_menu {
/** "Type" */
uint16_t type;
/** Description length */
uint8_t desc_len;
/** Description */
char desc[0];
} __attribute__ (( packed ));

/** PXE boot menu prompt */
#define DHCP_PXE_BOOT_MENU_PROMPT DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 10 )

/** PXE boot menu prompt */
struct dhcp_pxe_boot_menu_prompt {
/** Timeout
*
* A value of 0 means "time out immediately and select first
* boot item, without displaying the prompt". A value of 255
* means "display menu immediately with no timeout". Any
* other value means "display prompt, wait this many seconds
* for keypress, if key is F8, display menu, otherwise select
* first boot item".
*/
uint8_t timeout;
/** Prompt to press F8 */
char prompt[0];
} __attribute__ (( packed ));

/** PXE boot menu item */
#define DHCP_PXE_BOOT_MENU_ITEM DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 71 )

/** PXE boot menu item */
struct dhcp_pxe_boot_menu_item {
/** "Type"
*
* This field actually identifies the specific boot server (or
* cluster of boot servers offering identical boot files).
*/
uint16_t type;
/** "Layer"
*
* Just don't ask.
*/
uint16_t layer;
} __attribute__ (( packed ));

/** Requested IP address */
#define DHCP_REQUESTED_ADDRESS 50

Expand Down Expand Up @@ -140,6 +181,14 @@ struct dhcp_pxe_boot_menu_item;
/** Client identifier */
#define DHCP_CLIENT_ID 61

/** Client identifier */
struct dhcp_client_id {
/** Link-layer protocol */
uint8_t ll_proto;
/** Link-layer address */
uint8_t ll_addr[MAX_LL_ADDR_LEN];
} __attribute__ (( packed ));

/** TFTP server name
*
* This option replaces the fixed "sname" field, when that field is
Expand All @@ -163,6 +212,16 @@ struct dhcp_pxe_boot_menu_item;
/** UUID client identifier */
#define DHCP_CLIENT_UUID 97

/** UUID client identifier */
struct dhcp_client_uuid {
/** Identifier type */
uint8_t type;
/** UUID */
union uuid uuid;
} __attribute__ (( packed ));

#define DHCP_CLIENT_UUID_TYPE 0

/** Etherboot-specific encapsulated options
*
* This encapsulated options field is used to contain all options
Expand Down Expand Up @@ -213,7 +272,7 @@ struct dhcp_pxe_boot_menu_item;
/** Skip PXE DHCP protocol extensions such as ProxyDHCP
*
* If set to a non-zero value, gPXE will not wait for ProxyDHCP offers
* and will ignore any PXE-specific DHCP offers that it receives.
* and will ignore any PXE-specific DHCP options that it receives.
*/
#define DHCP_EB_NO_PXEDHCP DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb0 )

Expand All @@ -230,6 +289,16 @@ struct dhcp_pxe_boot_menu_item;
*/
#define DHCP_EB_BUS_ID DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb1 )

/** Network device descriptor */
struct dhcp_netdev_desc {
/** Bus type ID */
uint8_t type;
/** Vendor ID */
uint16_t vendor;
/** Device ID */
uint16_t device;
} __attribute__ (( packed ));

/** BIOS drive number
*
* This is the drive number for a drive emulated via INT 13. 0x80 is
Expand Down Expand Up @@ -480,33 +549,32 @@ struct dhcphdr {
*/
#define DHCP_MIN_LEN 552

/** Maximum time that we will wait for ProxyDHCP responses */
#define PROXYDHCP_WAIT_TIME ( 2 * TICKS_PER_SEC )

/** Timeouts for sending DHCP packets */
#define DHCP_MIN_TIMEOUT ( 1 * TICKS_PER_SEC )
#define DHCP_MAX_TIMEOUT ( 10 * TICKS_PER_SEC )

/** Maximum time that we will wait for ProxyDHCP responses */
#define PROXYDHCP_MAX_TIMEOUT ( 2 * TICKS_PER_SEC )

/** Settings block name used for DHCP responses */
#define DHCP_SETTINGS_NAME "dhcp"

/** Settings block name used for ProxyDHCP responses */
#define PROXYDHCP_SETTINGS_NAME "proxydhcp"

/** Setting block name used for BootServerDHCP responses */
#define BSDHCP_SETTINGS_NAME "bs"
#define PXEBS_SETTINGS_NAME "pxebs"

extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
struct net_device *netdev, uint8_t msgtype,
struct dhcp_options *options,
const void *options, size_t options_len,
void *data, size_t max_len );
extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
struct net_device *netdev,
unsigned int msgtype, struct in_addr ciaddr,
struct in_addr server,
struct in_addr requested_ip,
struct dhcp_pxe_boot_menu_item *menu_item,
void *data, size_t max_len );
extern int start_dhcp ( struct job_interface *job, struct net_device *netdev );
extern int start_pxebs ( struct job_interface *job, struct net_device *netdev,
struct in_addr pxe_server, unsigned int pxe_type );

#endif /* _GPXE_DHCP_H */
31 changes: 29 additions & 2 deletions src/include/gpxe/dhcppkt.h
Expand Up @@ -9,27 +9,54 @@

#include <gpxe/dhcp.h>
#include <gpxe/dhcpopts.h>
#include <gpxe/refcnt.h>

/**
* A DHCP packet
*
*/
struct dhcp_packet {
/** Reference counter */
struct refcnt refcnt;
/** The DHCP packet contents */
struct dhcphdr *dhcphdr;
/** Maximum length of the DHCP packet buffer */
size_t max_len;
/** Used length of the DHCP packet buffer */
size_t len;
/** DHCP option blocks */
/** DHCP options */
struct dhcp_options options;
/** Settings interface */
struct settings settings;
};

/**
* Increment reference count on DHCP packet
*
* @v dhcppkt DHCP packet
* @ret dhcppkt DHCP packet
*/
static inline __attribute__ (( always_inline )) struct dhcp_packet *
dhcppkt_get ( struct dhcp_packet *dhcppkt ) {
ref_get ( &dhcppkt->refcnt );
return dhcppkt;
}

/**
* Decrement reference count on DHCP packet
*
* @v dhcppkt DHCP packet
*/
static inline __attribute__ (( always_inline )) void
dhcppkt_put ( struct dhcp_packet *dhcppkt ) {
ref_put ( &dhcppkt->refcnt );
}

extern int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
const void *data, size_t len );
extern int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
void *data, size_t len );
extern void dhcppkt_init ( struct dhcp_packet *dhcppkt,
void *data, size_t len );
struct dhcphdr *data, size_t len );

#endif /* _GPXE_DHCPPKT_H */

0 comments on commit e65afc4

Please sign in to comment.