Browse Source

[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.
tags/v0.9.7
Michael Brown 16 years ago
parent
commit
e65afc4b10

+ 1
- 1
src/arch/i386/interface/pxe/pxe_preboot.c View File

82
 static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = {
82
 static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = {
83
 	[CACHED_INFO_DHCPDISCOVER] = { create_fakedhcpdiscover },
83
 	[CACHED_INFO_DHCPDISCOVER] = { create_fakedhcpdiscover },
84
 	[CACHED_INFO_DHCPACK] = { create_fakedhcpack },
84
 	[CACHED_INFO_DHCPACK] = { create_fakedhcpack },
85
-	[CACHED_INFO_BINL] = { create_fakeproxydhcpack },
85
+	[CACHED_INFO_BINL] = { create_fakepxebsack },
86
 };
86
 };
87
 
87
 
88
 /* The case in which the caller doesn't supply a buffer is really
88
 /* The case in which the caller doesn't supply a buffer is really

+ 94
- 5
src/hci/commands/dhcp_cmd.c View File

26
 #include <assert.h>
26
 #include <assert.h>
27
 #include <getopt.h>
27
 #include <getopt.h>
28
 #include <gpxe/netdevice.h>
28
 #include <gpxe/netdevice.h>
29
+#include <gpxe/in.h>
29
 #include <gpxe/command.h>
30
 #include <gpxe/command.h>
30
 #include <usr/dhcpmgmt.h>
31
 #include <usr/dhcpmgmt.h>
31
 
32
 
60
 		{ "help", 0, NULL, 'h' },
61
 		{ "help", 0, NULL, 'h' },
61
 		{ NULL, 0, NULL, 0 },
62
 		{ NULL, 0, NULL, 0 },
62
 	};
63
 	};
63
-	const char *name;
64
+	const char *netdev_txt;
64
 	struct net_device *netdev;
65
 	struct net_device *netdev;
65
 	int c;
66
 	int c;
66
 	int rc;
67
 	int rc;
82
 		dhcp_syntax ( argv );
83
 		dhcp_syntax ( argv );
83
 		return 1;
84
 		return 1;
84
 	}
85
 	}
85
-	name = argv[optind];
86
+	netdev_txt = argv[optind];
86
 
87
 
87
-	/* Perform DHCP */
88
-	netdev = find_netdev ( name );
88
+	/* Parse arguments */
89
+	netdev = find_netdev ( netdev_txt );
89
 	if ( ! netdev ) {
90
 	if ( ! netdev ) {
90
-		printf ( "No such interface: %s\n", name );
91
+		printf ( "No such interface: %s\n", netdev_txt );
91
 		return 1;
92
 		return 1;
92
 	}
93
 	}
94
+
95
+	/* Perform DHCP */
93
 	if ( ( rc = dhcp ( netdev ) ) != 0 ) {
96
 	if ( ( rc = dhcp ( netdev ) ) != 0 ) {
94
 		printf ( "Could not configure %s: %s\n", netdev->name,
97
 		printf ( "Could not configure %s: %s\n", netdev->name,
95
 			 strerror ( rc ) );
98
 			 strerror ( rc ) );
99
 	return 0;
102
 	return 0;
100
 }
103
 }
101
 
104
 
105
+/**
106
+ * "pxebs" command syntax message
107
+ *
108
+ * @v argv		Argument list
109
+ */
110
+static void pxebs_syntax ( char **argv ) {
111
+	printf ( "Usage:\n"
112
+		 "  %s <interface> <discovery_ip> <server_type>\n"
113
+		 "\n"
114
+		 "Perform PXE Boot Server discovery\n",
115
+		 argv[0] );
116
+}
117
+
118
+/**
119
+ * The "pxebs" command
120
+ *
121
+ * @v argc		Argument count
122
+ * @v argv		Argument list
123
+ * @ret rc		Exit code
124
+ */
125
+static int pxebs_exec ( int argc, char **argv ) {
126
+	static struct option longopts[] = {
127
+		{ "help", 0, NULL, 'h' },
128
+		{ NULL, 0, NULL, 0 },
129
+	};
130
+	const char *netdev_txt;
131
+	const char *pxe_server_txt;
132
+	const char *pxe_type_txt;
133
+	struct net_device *netdev;
134
+	struct in_addr pxe_server;
135
+	unsigned int pxe_type;
136
+	char *end;
137
+	int c;
138
+	int rc;
139
+
140
+	/* Parse options */
141
+	while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
142
+		switch ( c ) {
143
+		case 'h':
144
+			/* Display help text */
145
+		default:
146
+			/* Unrecognised/invalid option */
147
+			pxebs_syntax ( argv );
148
+			return 1;
149
+		}
150
+	}
151
+
152
+	/* Need exactly one interface name remaining after the options */
153
+	if ( optind != ( argc - 3 ) ) {
154
+		pxebs_syntax ( argv );
155
+		return 1;
156
+	}
157
+	netdev_txt = argv[optind];
158
+	pxe_server_txt = argv[ optind + 1 ];
159
+	pxe_type_txt = argv[ optind + 2 ];
160
+
161
+	/* Parse arguments */
162
+	netdev = find_netdev ( netdev_txt );
163
+	if ( ! netdev ) {
164
+		printf ( "No such interface: %s\n", netdev_txt );
165
+		return 1;
166
+	}
167
+	if ( inet_aton ( pxe_server_txt, &pxe_server ) == 0 ) {
168
+		printf ( "Bad discovery IP address: %s\n", pxe_server_txt );
169
+		return 1;
170
+	}
171
+	pxe_type = strtoul ( pxe_type_txt, &end, 0 );
172
+	if ( *end ) {
173
+		printf ( "Bad server type: %s\n", pxe_type_txt );
174
+		return 1;
175
+	}
176
+
177
+	/* Perform Boot Server Discovery */
178
+	if ( ( rc = pxebs ( netdev, pxe_server, pxe_type ) ) != 0 ) {
179
+		printf ( "Could not discover boot server on %s: %s\n",
180
+			 netdev->name, strerror ( rc ) );
181
+		return 1;
182
+	}
183
+
184
+	return 0;
185
+}
186
+
102
 /** DHCP management commands */
187
 /** DHCP management commands */
103
 struct command dhcp_commands[] __command = {
188
 struct command dhcp_commands[] __command = {
104
 	{
189
 	{
105
 		.name = "dhcp",
190
 		.name = "dhcp",
106
 		.exec = dhcp_exec,
191
 		.exec = dhcp_exec,
107
 	},
192
 	},
193
+	{
194
+		.name = "pxebs",
195
+		.exec = pxebs_exec,
196
+	},
108
 };
197
 };

+ 1
- 1
src/hci/mucurses/ansi_screen.c View File

15
 	scr->attrs = 0;
15
 	scr->attrs = 0;
16
 	scr->curs_x = 0;
16
 	scr->curs_x = 0;
17
 	scr->curs_y = 0;
17
 	scr->curs_y = 0;
18
-	printf ( "\033[0m\033[2J\033[1;1H" );
18
+	printf ( "\033[0m" );
19
 }
19
 }
20
 
20
 
21
 static void ansiscr_movetoyx ( struct _curses_screen *scr,
21
 static void ansiscr_movetoyx ( struct _curses_screen *scr,

+ 2
- 2
src/hci/mucurses/wininit.c View File

18
 	stdscr->scr->init( stdscr->scr );
18
 	stdscr->scr->init( stdscr->scr );
19
 	stdscr->height = LINES;
19
 	stdscr->height = LINES;
20
 	stdscr->width = COLS;
20
 	stdscr->width = COLS;
21
-	erase();
21
+	move ( 0, 0 );
22
 	return stdscr;
22
 	return stdscr;
23
 }
23
 }
24
 
24
 
29
 int endwin ( void ) {
29
 int endwin ( void ) {
30
 	attrset ( 0 );
30
 	attrset ( 0 );
31
 	color_set ( 0, NULL );
31
 	color_set ( 0, NULL );
32
-	erase();
32
+	mvprintw ( ( LINES - 1 ), 0, "\n" );
33
 	stdscr->scr->exit( stdscr->scr );
33
 	stdscr->scr->exit( stdscr->scr );
34
 	return OK;
34
 	return OK;
35
 }
35
 }

+ 79
- 11
src/include/gpxe/dhcp.h View File

12
 #include <gpxe/list.h>
12
 #include <gpxe/list.h>
13
 #include <gpxe/refcnt.h>
13
 #include <gpxe/refcnt.h>
14
 #include <gpxe/tables.h>
14
 #include <gpxe/tables.h>
15
+#include <gpxe/uuid.h>
16
+#include <gpxe/netdevice.h>
15
 
17
 
16
-struct net_device;
17
 struct job_interface;
18
 struct job_interface;
18
 struct dhcp_options;
19
 struct dhcp_options;
19
 struct dhcp_packet;
20
 struct dhcp_packet;
20
-struct dhcp_pxe_boot_menu_item;
21
 
21
 
22
 /** BOOTP/DHCP server port */
22
 /** BOOTP/DHCP server port */
23
 #define BOOTPS_PORT 67
23
 #define BOOTPS_PORT 67
88
 /** PXE boot menu */
88
 /** PXE boot menu */
89
 #define DHCP_PXE_BOOT_MENU DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 9 )
89
 #define DHCP_PXE_BOOT_MENU DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 9 )
90
 
90
 
91
+/** PXE boot menu */
92
+struct dhcp_pxe_boot_menu {
93
+	/** "Type" */
94
+	uint16_t type;
95
+	/** Description length */
96
+	uint8_t desc_len;
97
+	/** Description */
98
+	char desc[0];
99
+} __attribute__ (( packed ));
100
+
91
 /** PXE boot menu prompt */
101
 /** PXE boot menu prompt */
92
 #define DHCP_PXE_BOOT_MENU_PROMPT DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 10 )
102
 #define DHCP_PXE_BOOT_MENU_PROMPT DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 10 )
93
 
103
 
104
+/** PXE boot menu prompt */
105
+struct dhcp_pxe_boot_menu_prompt {
106
+	/** Timeout
107
+	 *
108
+	 * A value of 0 means "time out immediately and select first
109
+	 * boot item, without displaying the prompt".  A value of 255
110
+	 * means "display menu immediately with no timeout".  Any
111
+	 * other value means "display prompt, wait this many seconds
112
+	 * for keypress, if key is F8, display menu, otherwise select
113
+	 * first boot item".
114
+	 */
115
+	uint8_t timeout;
116
+	/** Prompt to press F8 */
117
+	char prompt[0];
118
+} __attribute__ (( packed ));
119
+
94
 /** PXE boot menu item */
120
 /** PXE boot menu item */
95
 #define DHCP_PXE_BOOT_MENU_ITEM DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 71 )
121
 #define DHCP_PXE_BOOT_MENU_ITEM DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 71 )
96
 
122
 
123
+/** PXE boot menu item */
124
+struct dhcp_pxe_boot_menu_item {
125
+	/** "Type"
126
+	 *
127
+	 * This field actually identifies the specific boot server (or
128
+	 * cluster of boot servers offering identical boot files).
129
+	 */
130
+	uint16_t type;
131
+	/** "Layer"
132
+	 *
133
+	 * Just don't ask.
134
+	 */
135
+	uint16_t layer;
136
+} __attribute__ (( packed ));
137
+
97
 /** Requested IP address */
138
 /** Requested IP address */
98
 #define DHCP_REQUESTED_ADDRESS 50
139
 #define DHCP_REQUESTED_ADDRESS 50
99
 
140
 
140
 /** Client identifier */
181
 /** Client identifier */
141
 #define DHCP_CLIENT_ID 61
182
 #define DHCP_CLIENT_ID 61
142
 
183
 
184
+/** Client identifier */
185
+struct dhcp_client_id {
186
+	/** Link-layer protocol */
187
+	uint8_t ll_proto;
188
+	/** Link-layer address */
189
+	uint8_t ll_addr[MAX_LL_ADDR_LEN];
190
+} __attribute__ (( packed ));
191
+
143
 /** TFTP server name
192
 /** TFTP server name
144
  *
193
  *
145
  * This option replaces the fixed "sname" field, when that field is
194
  * This option replaces the fixed "sname" field, when that field is
163
 /** UUID client identifier */
212
 /** UUID client identifier */
164
 #define DHCP_CLIENT_UUID 97
213
 #define DHCP_CLIENT_UUID 97
165
 
214
 
215
+/** UUID client identifier */
216
+struct dhcp_client_uuid {
217
+	/** Identifier type */
218
+	uint8_t type;
219
+	/** UUID */
220
+	union uuid uuid;
221
+} __attribute__ (( packed ));
222
+
223
+#define DHCP_CLIENT_UUID_TYPE 0
224
+
166
 /** Etherboot-specific encapsulated options
225
 /** Etherboot-specific encapsulated options
167
  *
226
  *
168
  * This encapsulated options field is used to contain all options
227
  * This encapsulated options field is used to contain all options
213
 /** Skip PXE DHCP protocol extensions such as ProxyDHCP
272
 /** Skip PXE DHCP protocol extensions such as ProxyDHCP
214
  *
273
  *
215
  * If set to a non-zero value, gPXE will not wait for ProxyDHCP offers
274
  * If set to a non-zero value, gPXE will not wait for ProxyDHCP offers
216
- * and will ignore any PXE-specific DHCP offers that it receives.
275
+ * and will ignore any PXE-specific DHCP options that it receives.
217
  */
276
  */
218
 #define DHCP_EB_NO_PXEDHCP DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb0 )
277
 #define DHCP_EB_NO_PXEDHCP DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb0 )
219
 
278
 
230
  */
289
  */
231
 #define DHCP_EB_BUS_ID DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb1 )
290
 #define DHCP_EB_BUS_ID DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb1 )
232
 
291
 
292
+/** Network device descriptor */
293
+struct dhcp_netdev_desc {
294
+	/** Bus type ID */
295
+	uint8_t type;
296
+	/** Vendor ID */
297
+	uint16_t vendor;
298
+	/** Device ID */
299
+	uint16_t device;
300
+} __attribute__ (( packed ));
301
+
233
 /** BIOS drive number
302
 /** BIOS drive number
234
  *
303
  *
235
  * This is the drive number for a drive emulated via INT 13.  0x80 is
304
  * This is the drive number for a drive emulated via INT 13.  0x80 is
480
  */
549
  */
481
 #define DHCP_MIN_LEN 552
550
 #define DHCP_MIN_LEN 552
482
 
551
 
483
-/** Maximum time that we will wait for ProxyDHCP responses */
484
-#define PROXYDHCP_WAIT_TIME ( 2 * TICKS_PER_SEC )
485
-
486
 /** Timeouts for sending DHCP packets */
552
 /** Timeouts for sending DHCP packets */
487
 #define DHCP_MIN_TIMEOUT ( 1 * TICKS_PER_SEC )
553
 #define DHCP_MIN_TIMEOUT ( 1 * TICKS_PER_SEC )
488
 #define DHCP_MAX_TIMEOUT ( 10 * TICKS_PER_SEC )
554
 #define DHCP_MAX_TIMEOUT ( 10 * TICKS_PER_SEC )
489
 
555
 
556
+/** Maximum time that we will wait for ProxyDHCP responses */
557
+#define PROXYDHCP_MAX_TIMEOUT ( 2 * TICKS_PER_SEC )
558
+
490
 /** Settings block name used for DHCP responses */
559
 /** Settings block name used for DHCP responses */
491
 #define DHCP_SETTINGS_NAME "dhcp"
560
 #define DHCP_SETTINGS_NAME "dhcp"
492
 
561
 
494
 #define PROXYDHCP_SETTINGS_NAME "proxydhcp"
563
 #define PROXYDHCP_SETTINGS_NAME "proxydhcp"
495
 
564
 
496
 /** Setting block name used for BootServerDHCP responses */
565
 /** Setting block name used for BootServerDHCP responses */
497
-#define BSDHCP_SETTINGS_NAME "bs"
566
+#define PXEBS_SETTINGS_NAME "pxebs"
498
 
567
 
499
 extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
568
 extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
500
 				struct net_device *netdev, uint8_t msgtype,
569
 				struct net_device *netdev, uint8_t msgtype,
501
-				struct dhcp_options *options, 
570
+				const void *options, size_t options_len,
502
 				void *data, size_t max_len );
571
 				void *data, size_t max_len );
503
 extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
572
 extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
504
 				 struct net_device *netdev,
573
 				 struct net_device *netdev,
505
 				 unsigned int msgtype, struct in_addr ciaddr,
574
 				 unsigned int msgtype, struct in_addr ciaddr,
506
-				 struct in_addr server,
507
-				 struct in_addr requested_ip,
508
-				 struct dhcp_pxe_boot_menu_item *menu_item,
509
 				 void *data, size_t max_len );
575
 				 void *data, size_t max_len );
510
 extern int start_dhcp ( struct job_interface *job, struct net_device *netdev );
576
 extern int start_dhcp ( struct job_interface *job, struct net_device *netdev );
577
+extern int start_pxebs ( struct job_interface *job, struct net_device *netdev,
578
+			 struct in_addr pxe_server, unsigned int pxe_type );
511
 
579
 
512
 #endif /* _GPXE_DHCP_H */
580
 #endif /* _GPXE_DHCP_H */

+ 29
- 2
src/include/gpxe/dhcppkt.h View File

9
 
9
 
10
 #include <gpxe/dhcp.h>
10
 #include <gpxe/dhcp.h>
11
 #include <gpxe/dhcpopts.h>
11
 #include <gpxe/dhcpopts.h>
12
+#include <gpxe/refcnt.h>
12
 
13
 
13
 /**
14
 /**
14
  * A DHCP packet
15
  * A DHCP packet
15
  *
16
  *
16
  */
17
  */
17
 struct dhcp_packet {
18
 struct dhcp_packet {
19
+	/** Reference counter */
20
+	struct refcnt refcnt;
18
 	/** The DHCP packet contents */
21
 	/** The DHCP packet contents */
19
 	struct dhcphdr *dhcphdr;
22
 	struct dhcphdr *dhcphdr;
20
 	/** Maximum length of the DHCP packet buffer */
23
 	/** Maximum length of the DHCP packet buffer */
21
 	size_t max_len;
24
 	size_t max_len;
22
 	/** Used length of the DHCP packet buffer */
25
 	/** Used length of the DHCP packet buffer */
23
 	size_t len;
26
 	size_t len;
24
-	/** DHCP option blocks */
27
+	/** DHCP options */
25
 	struct dhcp_options options;
28
 	struct dhcp_options options;
29
+	/** Settings interface */
30
+	struct settings settings;
26
 };
31
 };
27
 
32
 
33
+/**
34
+ * Increment reference count on DHCP packet
35
+ *
36
+ * @v dhcppkt		DHCP packet
37
+ * @ret dhcppkt		DHCP packet
38
+ */
39
+static inline __attribute__ (( always_inline )) struct dhcp_packet *
40
+dhcppkt_get ( struct dhcp_packet *dhcppkt ) {
41
+	ref_get ( &dhcppkt->refcnt );
42
+	return dhcppkt;
43
+}
44
+
45
+/**
46
+ * Decrement reference count on DHCP packet
47
+ *
48
+ * @v dhcppkt		DHCP packet
49
+ */
50
+static inline __attribute__ (( always_inline )) void
51
+dhcppkt_put ( struct dhcp_packet *dhcppkt ) {
52
+	ref_put ( &dhcppkt->refcnt );
53
+}
54
+
28
 extern int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
55
 extern int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
29
 			   const void *data, size_t len );
56
 			   const void *data, size_t len );
30
 extern int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
57
 extern int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
31
 			   void *data, size_t len );
58
 			   void *data, size_t len );
32
 extern void dhcppkt_init ( struct dhcp_packet *dhcppkt, 
59
 extern void dhcppkt_init ( struct dhcp_packet *dhcppkt, 
33
-			   void *data, size_t len );
60
+			   struct dhcphdr *data, size_t len );
34
 
61
 
35
 #endif /* _GPXE_DHCPPKT_H */
62
 #endif /* _GPXE_DHCPPKT_H */

+ 1
- 0
src/include/gpxe/errfile.h View File

167
 #define ERRFILE_smbios		      ( ERRFILE_OTHER | 0x00120000 )
167
 #define ERRFILE_smbios		      ( ERRFILE_OTHER | 0x00120000 )
168
 #define ERRFILE_smbios_settings	      ( ERRFILE_OTHER | 0x00130000 )
168
 #define ERRFILE_smbios_settings	      ( ERRFILE_OTHER | 0x00130000 )
169
 #define ERRFILE_efi_smbios	      ( ERRFILE_OTHER | 0x00140000 )
169
 #define ERRFILE_efi_smbios	      ( ERRFILE_OTHER | 0x00140000 )
170
+#define ERRFILE_pxemenu		      ( ERRFILE_OTHER | 0x00150000 )
170
 
171
 
171
 /** @} */
172
 /** @} */
172
 
173
 

+ 2
- 2
src/include/gpxe/fakedhcp.h View File

15
 				     void *data, size_t max_len );
15
 				     void *data, size_t max_len );
16
 extern int create_fakedhcpack ( struct net_device *netdev,
16
 extern int create_fakedhcpack ( struct net_device *netdev,
17
 				void *data, size_t max_len );
17
 				void *data, size_t max_len );
18
-extern int create_fakeproxydhcpack ( struct net_device *netdev,
19
-				     void *data, size_t max_len );
18
+extern int create_fakepxebsack ( struct net_device *netdev,
19
+				 void *data, size_t max_len );
20
 
20
 
21
 #endif /* _GPXE_FAKEDHCP_H */
21
 #endif /* _GPXE_FAKEDHCP_H */

+ 12
- 0
src/include/gpxe/settings.h View File

304
 	return storef_named_setting ( name, NULL );
304
 	return storef_named_setting ( name, NULL );
305
 }
305
 }
306
 
306
 
307
+/**
308
+ * Check existence of setting
309
+ *
310
+ * @v settings		Settings block, or NULL to search all blocks
311
+ * @v setting		Setting to fetch
312
+ * @ret exists		Setting exists
313
+ */
314
+static inline int setting_exists ( struct settings *settings,
315
+				   struct setting *setting ) {
316
+	return ( fetch_setting_len ( settings, setting ) >= 0 );
317
+}
318
+
307
 #endif /* _GPXE_SETTINGS_H */
319
 #endif /* _GPXE_SETTINGS_H */

+ 6
- 0
src/include/usr/autoboot.h View File

7
  *
7
  *
8
  */
8
  */
9
 
9
 
10
+#include <gpxe/in.h>
11
+struct net_device;
12
+
10
 extern int shutdown_exit_flags;
13
 extern int shutdown_exit_flags;
11
 
14
 
12
 extern void autoboot ( void );
15
 extern void autoboot ( void );
16
+extern int boot_next_server_and_filename ( struct in_addr next_server,
17
+					   const char *filename );
13
 extern int boot_root_path ( const char *root_path );
18
 extern int boot_root_path ( const char *root_path );
19
+extern int pxe_menu_boot ( struct net_device *netdev );
14
 
20
 
15
 #endif /* _USR_AUTOBOOT_H */
21
 #endif /* _USR_AUTOBOOT_H */

+ 3
- 1
src/include/usr/dhcpmgmt.h View File

9
 
9
 
10
 struct net_device;
10
 struct net_device;
11
 
11
 
12
-int dhcp ( struct net_device *netdev );
12
+extern int dhcp ( struct net_device *netdev );
13
+extern int pxebs ( struct net_device *netdev, struct in_addr pxe_server,
14
+		   unsigned int pxe_type );
13
 
15
 
14
 #endif /* _USR_DHCPMGMT_H */
16
 #endif /* _USR_DHCPMGMT_H */

+ 71
- 7
src/net/dhcppkt.c View File

32
  *
32
  *
33
  */
33
  */
34
 
34
 
35
+/****************************************************************************
36
+ *
37
+ * DHCP packet raw interface
38
+ *
39
+ */
40
+
35
 /**
41
 /**
36
  * Calculate used length of an IPv4 field within a DHCP packet
42
  * Calculate used length of an IPv4 field within a DHCP packet
37
  *
43
  *
193
 	return dhcpopt_fetch ( &dhcppkt->options, tag, data, len );
199
 	return dhcpopt_fetch ( &dhcppkt->options, tag, data, len );
194
 }
200
 }
195
 
201
 
202
+/****************************************************************************
203
+ *
204
+ * DHCP packet settings interface
205
+ *
206
+ */
207
+
208
+/**
209
+ * Store value of DHCP setting
210
+ *
211
+ * @v settings		Settings block
212
+ * @v setting		Setting to store
213
+ * @v data		Setting data, or NULL to clear setting
214
+ * @v len		Length of setting data
215
+ * @ret rc		Return status code
216
+ */
217
+static int dhcppkt_settings_store ( struct settings *settings,
218
+				    struct setting *setting,
219
+				    const void *data, size_t len ) {
220
+	struct dhcp_packet *dhcppkt =
221
+		container_of ( settings, struct dhcp_packet, settings );
222
+
223
+	return dhcppkt_store ( dhcppkt, setting->tag, data, len );
224
+}
225
+
226
+/**
227
+ * Fetch value of DHCP setting
228
+ *
229
+ * @v settings		Settings block, or NULL to search all blocks
230
+ * @v setting		Setting to fetch
231
+ * @v data		Buffer to fill with setting data
232
+ * @v len		Length of buffer
233
+ * @ret len		Length of setting data, or negative error
234
+ */
235
+static int dhcppkt_settings_fetch ( struct settings *settings,
236
+				    struct setting *setting,
237
+				    void *data, size_t len ) {
238
+	struct dhcp_packet *dhcppkt =
239
+		container_of ( settings, struct dhcp_packet, settings );
240
+
241
+	return dhcppkt_fetch ( dhcppkt, setting->tag, data, len );
242
+}
243
+
244
+/** DHCP settings operations */
245
+static struct settings_operations dhcppkt_settings_operations = {
246
+	.store = dhcppkt_settings_store,
247
+	.fetch = dhcppkt_settings_fetch,
248
+};
249
+
250
+/****************************************************************************
251
+ *
252
+ * Constructor
253
+ *
254
+ */
255
+
196
 /**
256
 /**
197
- * Initialise prepopulated DHCP packet
257
+ * Initialise DHCP packet
198
  *
258
  *
199
- * @v dhcppkt		Uninitialised DHCP packet
200
- * @v data		Memory for DHCP packet data
201
- * @v max_len		Length of memory for DHCP packet data
259
+ * @v dhcppkt		DHCP packet structure to fill in
260
+ * @v data		DHCP packet raw data
261
+ * @v max_len		Length of raw data buffer
202
  *
262
  *
203
- * The memory content must already be filled with valid DHCP options.
204
- * A zeroed block counts as a block of valid DHCP options.
263
+ * Initialise a DHCP packet structure from a data buffer containing a
264
+ * DHCP packet.
205
  */
265
  */
206
-void dhcppkt_init ( struct dhcp_packet *dhcppkt, void *data, size_t len ) {
266
+void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct dhcphdr *data,
267
+		    size_t len ) {
207
 	dhcppkt->dhcphdr = data;
268
 	dhcppkt->dhcphdr = data;
208
 	dhcppkt->max_len = len;
269
 	dhcppkt->max_len = len;
209
 	dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options,
270
 	dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options,
210
 		       ( len - offsetof ( struct dhcphdr, options ) ) );
271
 		       ( len - offsetof ( struct dhcphdr, options ) ) );
211
 	dhcppkt->len = ( offsetof ( struct dhcphdr, options ) +
272
 	dhcppkt->len = ( offsetof ( struct dhcphdr, options ) +
212
 			 dhcppkt->options.len );
273
 			 dhcppkt->options.len );
274
+	settings_init ( &dhcppkt->settings,
275
+			&dhcppkt_settings_operations, &dhcppkt->refcnt,
276
+			DHCP_SETTINGS_NAME, 0 );
213
 }
277
 }

+ 24
- 25
src/net/fakedhcp.c View File

108
 int create_fakedhcpdiscover ( struct net_device *netdev,
108
 int create_fakedhcpdiscover ( struct net_device *netdev,
109
 			      void *data, size_t max_len ) {
109
 			      void *data, size_t max_len ) {
110
 	struct dhcp_packet dhcppkt;
110
 	struct dhcp_packet dhcppkt;
111
-	struct in_addr dummy_addr = { 0 };
111
+	struct in_addr ciaddr = { 0 };
112
 	int rc;
112
 	int rc;
113
 
113
 
114
 	if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER,
114
 	if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER,
115
-					  dummy_addr, dummy_addr, dummy_addr,
116
-					  NULL, data, max_len ) ) != 0 ) {
115
+					  ciaddr, data, max_len ) ) != 0 ) {
117
 		DBG ( "Could not create DHCPDISCOVER: %s\n",
116
 		DBG ( "Could not create DHCPDISCOVER: %s\n",
118
 		      strerror ( rc ) );
117
 		      strerror ( rc ) );
119
 		return rc;
118
 		return rc;
138
 	int rc;
137
 	int rc;
139
 
138
 
140
 	/* Create base DHCPACK packet */
139
 	/* Create base DHCPACK packet */
141
-	if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL,
140
+	if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
142
 					 data, max_len ) ) != 0 ) {
141
 					 data, max_len ) ) != 0 ) {
143
 		DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
142
 		DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
144
 		return rc;
143
 		return rc;
164
 }
163
 }
165
 
164
 
166
 /**
165
 /**
167
- * Create ProxyDHCPACK packet
166
+ * Create fake PXE Boot Server ACK packet
168
  *
167
  *
169
  * @v netdev		Network device
168
  * @v netdev		Network device
170
  * @v data		Buffer for DHCP packet
169
  * @v data		Buffer for DHCP packet
173
  *
172
  *
174
  * Used by external code.
173
  * Used by external code.
175
  */
174
  */
176
-int create_fakeproxydhcpack ( struct net_device *netdev,
177
-			      void *data, size_t max_len ) {
175
+int create_fakepxebsack ( struct net_device *netdev,
176
+			  void *data, size_t max_len ) {
178
 	struct dhcp_packet dhcppkt;
177
 	struct dhcp_packet dhcppkt;
179
-	struct settings *settings;
180
-	struct settings *bs_settings;
178
+	struct settings *proxy_settings;
179
+	struct settings *pxebs_settings;
181
 	int rc;
180
 	int rc;
182
 
181
 
183
-	/* Identify ProxyDHCP settings */
184
-	settings = find_settings ( PROXYDHCP_SETTINGS_NAME );
185
-
186
-	/* No ProxyDHCP settings => use normal DHCPACK */
187
-	if ( ! settings )
182
+	/* Identify available settings */
183
+	proxy_settings = find_settings ( PROXYDHCP_SETTINGS_NAME );
184
+	pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME );
185
+	if ( ( ! proxy_settings ) && ( ! pxebs_settings ) ) {
186
+		/* No PXE boot server; return the regular DHCPACK */
188
 		return create_fakedhcpack ( netdev, data, max_len );
187
 		return create_fakedhcpack ( netdev, data, max_len );
188
+	}
189
 
189
 
190
 	/* Create base DHCPACK packet */
190
 	/* Create base DHCPACK packet */
191
-	if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL,
191
+	if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
192
 					 data, max_len ) ) != 0 ) {
192
 					 data, max_len ) ) != 0 ) {
193
-		DBG ( "Could not create ProxyDHCPACK: %s\n",
193
+		DBG ( "Could not create PXE BS ACK: %s\n",
194
 		      strerror ( rc ) );
194
 		      strerror ( rc ) );
195
 		return rc;
195
 		return rc;
196
 	}
196
 	}
197
 
197
 
198
 	/* Merge in ProxyDHCP options */
198
 	/* Merge in ProxyDHCP options */
199
-	if ( ( rc = copy_settings ( &dhcppkt, settings ) ) != 0 ) {
200
-		DBG ( "Could not set ProxyDHCPACK settings: %s\n",
199
+	if ( proxy_settings &&
200
+	     ( ( rc = copy_settings ( &dhcppkt, proxy_settings ) ) != 0 ) ) {
201
+		DBG ( "Could not copy ProxyDHCP settings: %s\n",
201
 		      strerror ( rc ) );
202
 		      strerror ( rc ) );
202
 		return rc;
203
 		return rc;
203
 	}
204
 	}
204
 
205
 
205
 	/* Merge in BootServerDHCP options, if present */
206
 	/* Merge in BootServerDHCP options, if present */
206
-	bs_settings = find_settings ( BSDHCP_SETTINGS_NAME );
207
-	if ( bs_settings ) {
208
-		if ( ( rc = copy_settings ( &dhcppkt, bs_settings ) ) != 0 ) {
209
-			DBG ( "Could not set BootServerDHCPACK settings: "
210
-			      "%s\n", strerror ( rc ) );
211
-			return rc;
212
-		}
207
+	if ( pxebs_settings &&
208
+	     ( ( rc = copy_settings ( &dhcppkt, pxebs_settings ) ) != 0 ) ) {
209
+		DBG ( "Could not copy PXE BS settings: %s\n",
210
+		      strerror ( rc ) );
211
+		return rc;
213
 	}
212
 	}
214
 
213
 
215
 	return 0;
214
 	return 0;

+ 679
- 902
src/net/udp/dhcp.c
File diff suppressed because it is too large
View File


+ 13
- 2
src/usr/autoboot.c View File

89
  * @v filename		Boot filename
89
  * @v filename		Boot filename
90
  * @ret rc		Return status code
90
  * @ret rc		Return status code
91
  */
91
  */
92
-static int boot_next_server_and_filename ( struct in_addr next_server,
93
-					   const char *filename ) {
92
+int boot_next_server_and_filename ( struct in_addr next_server,
93
+				    const char *filename ) {
94
 	struct uri *uri;
94
 	struct uri *uri;
95
 	struct image *image;
95
 	struct image *image;
96
 	char buf[ 23 /* tftp://xxx.xxx.xxx.xxx/ */ + strlen(filename) + 1 ];
96
 	char buf[ 23 /* tftp://xxx.xxx.xxx.xxx/ */ + strlen(filename) + 1 ];
167
  * @ret rc		Return status code
167
  * @ret rc		Return status code
168
  */
168
  */
169
 static int netboot ( struct net_device *netdev ) {
169
 static int netboot ( struct net_device *netdev ) {
170
+	struct setting tmp_setting = { .name = NULL };
170
 	char buf[256];
171
 	char buf[256];
171
 	struct in_addr next_server;
172
 	struct in_addr next_server;
172
 	int rc;
173
 	int rc;
194
 	if ( rc != ENOENT )
195
 	if ( rc != ENOENT )
195
 		return rc;
196
 		return rc;
196
 
197
 
198
+	/* Try PXE menu boot, if we have PXE menu options */
199
+	tmp_setting.tag = DHCP_VENDOR_CLASS_ID;
200
+	fetch_string_setting ( NULL, &tmp_setting, buf, sizeof ( buf ) );
201
+	tmp_setting.tag = DHCP_PXE_BOOT_MENU;
202
+	if ( ( strcmp ( buf, "PXEClient" ) == 0 ) &&
203
+	     setting_exists ( NULL, &tmp_setting ) ) {
204
+		printf ( "Booting from PXE menu\n" );
205
+		return pxe_menu_boot ( netdev );
206
+	}
207
+
197
 	/* Try to download and boot whatever we are given as a filename */
208
 	/* Try to download and boot whatever we are given as a filename */
198
 	fetch_ipv4_setting ( NULL, &next_server_setting, &next_server );
209
 	fetch_ipv4_setting ( NULL, &next_server_setting, &next_server );
199
 	fetch_string_setting ( NULL, &filename_setting, buf, sizeof ( buf ) );
210
 	fetch_string_setting ( NULL, &filename_setting, buf, sizeof ( buf ) );

+ 14
- 0
src/usr/dhcpmgmt.c View File

46
 
46
 
47
 	return rc;
47
 	return rc;
48
 }
48
 }
49
+
50
+int pxebs ( struct net_device *netdev, struct in_addr pxe_server,
51
+	    unsigned int pxe_type ) {
52
+	int rc;
53
+
54
+	/* Perform PXE Boot Server Discovery */
55
+	printf ( "PXEBS (%s %s type %d)",
56
+		 netdev->name, inet_ntoa ( pxe_server ), pxe_type );
57
+	if ( ( rc = start_pxebs ( &monojob, netdev, pxe_server,
58
+				  pxe_type ) ) == 0 )
59
+		rc = monojob_wait ( "" );
60
+
61
+	return rc;
62
+}

+ 336
- 0
src/usr/pxemenu.c View File

1
+/*
2
+ * Copyright (C) 2009 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., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <stdint.h>
20
+#include <stdlib.h>
21
+#include <stdio.h>
22
+#include <string.h>
23
+#include <errno.h>
24
+#include <ctype.h>
25
+#include <byteswap.h>
26
+#include <curses.h>
27
+#include <console.h>
28
+#include <gpxe/dhcp.h>
29
+#include <gpxe/vsprintf.h>
30
+#include <gpxe/keys.h>
31
+#include <gpxe/timer.h>
32
+#include <usr/dhcpmgmt.h>
33
+#include <usr/autoboot.h>
34
+
35
+/** @file
36
+ *
37
+ * PXE Boot Menus
38
+ *
39
+ */
40
+
41
+/* Colour pairs */
42
+#define CPAIR_NORMAL	1
43
+#define CPAIR_SELECT	2
44
+
45
+/** A PXE boot menu item */
46
+struct pxe_menu_item {
47
+	/** Boot Server type */
48
+	unsigned int type;
49
+	/** Description */
50
+	char *desc;
51
+};
52
+
53
+/**
54
+ * A PXE boot menu
55
+ *
56
+ * This structure encapsulates the menu information provided via DHCP
57
+ * options.
58
+ */
59
+struct pxe_menu {
60
+	/** Boot Server address */
61
+	struct in_addr server;
62
+	/** Timeout (in seconds)
63
+	 *
64
+	 * Negative indicates no timeout (i.e. wait indefinitely)
65
+	 */
66
+	int timeout;
67
+	/** Number of menu items */
68
+	unsigned int num_items;
69
+	/** Selected menu item */
70
+	unsigned int selection;
71
+	/** Menu items */
72
+	struct pxe_menu_item items[0];
73
+};
74
+
75
+/**
76
+ * Parse and allocate PXE boot menu
77
+ *
78
+ * @v menu		PXE boot menu to fill in
79
+ * @ret rc		Return status code
80
+ *
81
+ * It is the callers responsibility to eventually free the allocated
82
+ * boot menu.
83
+ */
84
+static int pxe_menu_parse ( struct pxe_menu **menu ) {
85
+	struct setting tmp_setting = { .name = NULL };
86
+	struct in_addr server;
87
+	struct dhcp_pxe_boot_menu_prompt prompt = { .timeout = 0 };
88
+	uint8_t raw_menu[256];
89
+	int raw_menu_len;
90
+	struct dhcp_pxe_boot_menu *raw_menu_item;
91
+	void *raw_menu_end;
92
+	unsigned int num_menu_items;
93
+	unsigned int i;
94
+	int rc;
95
+
96
+	/* Fetch relevant settings */
97
+	tmp_setting.tag = DHCP_PXE_BOOT_SERVER_MCAST;
98
+	server.s_addr = INADDR_BROADCAST;
99
+	fetch_ipv4_setting ( NULL, &tmp_setting, &server );
100
+	tmp_setting.tag = DHCP_PXE_BOOT_MENU_PROMPT;
101
+	fetch_setting ( NULL, &tmp_setting, &prompt, sizeof ( prompt ) );
102
+	tmp_setting.tag = DHCP_PXE_BOOT_MENU;
103
+	memset ( raw_menu, 0, sizeof ( raw_menu ) );
104
+	if ( ( raw_menu_len = fetch_setting ( NULL, &tmp_setting, raw_menu,
105
+					      sizeof ( raw_menu ) ) ) < 0 ) {
106
+		rc = raw_menu_len;
107
+		DBG ( "Could not retrieve raw PXE boot menu: %s\n",
108
+		      strerror ( rc ) );
109
+		return rc;
110
+	}
111
+	if ( raw_menu_len >= ( int ) sizeof ( raw_menu ) ) {
112
+		DBG ( "Raw PXE boot menu too large for buffer\n" );
113
+		return -ENOSPC;
114
+	}
115
+	raw_menu_end = ( raw_menu + raw_menu_len );
116
+
117
+	/* Count menu items */
118
+	num_menu_items = 0;
119
+	raw_menu_item = ( ( void * ) raw_menu );
120
+	while ( 1 ) {
121
+		if ( ( ( ( void * ) raw_menu_item ) +
122
+		       sizeof ( *raw_menu_item ) ) > raw_menu_end )
123
+			break;
124
+		if ( ( ( ( void * ) raw_menu_item ) +
125
+		       sizeof ( *raw_menu_item ) +
126
+		       raw_menu_item->desc_len ) > raw_menu_end )
127
+			break;
128
+		num_menu_items++;
129
+		raw_menu_item = ( ( ( void * ) raw_menu_item ) +
130
+				  sizeof ( *raw_menu_item ) +
131
+				  raw_menu_item->desc_len );
132
+	}
133
+
134
+	/* Allocate space for parsed menu */
135
+	*menu = zalloc ( sizeof ( **menu ) +
136
+			 ( num_menu_items * sizeof ( (*menu)->items[0] ) ) +
137
+			 raw_menu_len + 1 /* NUL */ );
138
+	if ( ! *menu ) {
139
+		DBG ( "Could not allocate PXE boot menu\n" );
140
+		return -ENOMEM;
141
+	}
142
+
143
+	/* Fill in parsed menu */
144
+	(*menu)->server = server;
145
+	(*menu)->timeout =
146
+		( ( prompt.timeout == 0xff ) ? -1 : prompt.timeout );
147
+	(*menu)->num_items = num_menu_items;
148
+	raw_menu_item = ( ( ( void * ) (*menu) ) + sizeof ( **menu ) +
149
+			  ( num_menu_items * sizeof ( (*menu)->items[0] ) ) );
150
+	memcpy ( raw_menu_item, raw_menu, raw_menu_len );
151
+	for ( i = 0 ; i < num_menu_items ; i++ ) {
152
+		(*menu)->items[i].type = ntohs ( raw_menu_item->type );
153
+		(*menu)->items[i].desc = raw_menu_item->desc;
154
+		/* Set type to 0; this ensures that the description
155
+		 * for the previous menu item is NUL-terminated.
156
+		 * (Final item is NUL-terminated anyway.)
157
+		 */
158
+		raw_menu_item->type = 0;
159
+		raw_menu_item = ( ( ( void * ) raw_menu_item ) +
160
+				  sizeof ( *raw_menu_item ) +
161
+				  raw_menu_item->desc_len );
162
+	}
163
+
164
+	return 0;
165
+}
166
+
167
+/**
168
+ * Draw PXE boot menu item
169
+ *
170
+ * @v menu		PXE boot menu
171
+ * @v index		Index of item to draw
172
+ */
173
+static void pxe_menu_draw_item ( struct pxe_menu *menu,
174
+				 unsigned int index ) {
175
+	int selected = ( menu->selection == index );
176
+	char buf[COLS+1];
177
+	char *tmp = buf;
178
+	ssize_t remaining = sizeof ( buf );
179
+	size_t len;
180
+	unsigned int row;
181
+
182
+	/* Prepare space-padded row content */
183
+	len = ssnprintf ( tmp, remaining, " %c. %s",
184
+			  ( 'A' + index ), menu->items[index].desc );
185
+	tmp += len;
186
+	remaining -= len;
187
+	if ( selected && ( menu->timeout > 0 ) ) {
188
+		len = ssnprintf ( tmp, remaining, " (%d)", menu->timeout );
189
+		tmp += len;
190
+		remaining -= len;
191
+	}
192
+	for ( ; remaining > 1 ; tmp++, remaining-- )
193
+		*tmp = ' ';
194
+	*tmp = '\0';
195
+
196
+	/* Draw row */
197
+	row = ( LINES - menu->num_items + index );
198
+	color_set ( ( selected ? CPAIR_SELECT : CPAIR_NORMAL ), NULL );
199
+	mvprintw ( row, 0, "%s", buf );
200
+	move ( row, 1 );
201
+}
202
+
203
+/**
204
+ * Make selection from PXE boot menu
205
+ *
206
+ * @v menu		PXE boot menu
207
+ * @ret rc		Return status code
208
+ */
209
+int pxe_menu_select ( struct pxe_menu *menu ) {
210
+	unsigned long start = currticks();
211
+	unsigned long now;
212
+	unsigned long elapsed;
213
+	unsigned int old_selection;
214
+	int key;
215
+	unsigned int key_selection;
216
+	unsigned int i;
217
+	int rc = 0;
218
+
219
+	/* Initialise UI */
220
+	initscr();
221
+	start_color();
222
+	init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLACK );
223
+	init_pair ( CPAIR_SELECT, COLOR_BLACK, COLOR_WHITE );
224
+	color_set ( CPAIR_NORMAL, NULL );
225
+
226
+	/* Draw initial menu */
227
+	for ( i = 0 ; i < menu->num_items ; i++ )
228
+		printf ( "\n" );
229
+	for ( i = 0 ; i < menu->num_items ; i++ )
230
+		pxe_menu_draw_item ( menu, ( menu->num_items - i - 1 ) );
231
+
232
+	while ( 1 ) {
233
+
234
+		/* Decrease timeout if necessary */
235
+		if ( menu->timeout > 0 ) {
236
+			now = currticks();
237
+			elapsed = ( now - start );
238
+			if ( elapsed >= TICKS_PER_SEC ) {
239
+				start = now;
240
+				menu->timeout--;
241
+				pxe_menu_draw_item ( menu, menu->selection );
242
+			}
243
+		}
244
+
245
+		/* Select current item if we have timed out */
246
+		if ( menu->timeout == 0 )
247
+			break;
248
+
249
+		/* Check for keyboard input */
250
+		if ( ! iskey() )
251
+			continue;
252
+		key = getkey();
253
+
254
+		/* Any keyboard input cancels the timeout */
255
+		menu->timeout = -1;
256
+		pxe_menu_draw_item ( menu, menu->selection );
257
+
258
+		/* Act upon key */
259
+		old_selection = menu->selection;
260
+		if ( ( key == CR ) || ( key == LF ) ) {
261
+			break;
262
+		} else if ( key == CTRL_C ) {
263
+			rc = -ECANCELED;
264
+			break;
265
+		} else if ( key == KEY_UP ) {
266
+			if ( menu->selection > 0 )
267
+				menu->selection--;
268
+		} else if ( key == KEY_DOWN ) {
269
+			if ( menu->selection < ( menu->num_items - 1 ) )
270
+				menu->selection++;
271
+		} else if ( ( key < KEY_MIN ) &&
272
+			    ( ( key_selection = ( toupper ( key ) - 'A' ) )
273
+			      < menu->num_items ) ) {
274
+			menu->selection = key_selection;
275
+			menu->timeout = 0;
276
+		}
277
+		pxe_menu_draw_item ( menu, old_selection );
278
+		pxe_menu_draw_item ( menu, menu->selection );
279
+	}
280
+
281
+	/* Shut down UI */
282
+	endwin();
283
+
284
+	return rc;
285
+}
286
+
287
+/**
288
+ * Boot using PXE boot menu
289
+ *
290
+ * @ret rc		Return status code
291
+ *
292
+ * Note that a success return status indicates that a PXE boot menu
293
+ * item has been selected, and that the DHCP session should perform a
294
+ * boot server request/ack.
295
+ */
296
+int pxe_menu_boot ( struct net_device *netdev ) {
297
+	struct pxe_menu *menu;
298
+	struct in_addr pxe_server;
299
+	unsigned int pxe_type;
300
+	struct settings *pxebs_settings;
301
+	struct in_addr next_server;
302
+	char filename[256];
303
+	int rc;
304
+
305
+	/* Parse and allocate boot menu */
306
+	if ( ( rc = pxe_menu_parse ( &menu ) ) != 0 )
307
+		return rc;
308
+
309
+	/* Make selection from boot menu */
310
+	if ( ( rc = pxe_menu_select ( menu ) ) != 0 ) {
311
+		free ( menu );
312
+		return rc;
313
+	}
314
+	pxe_server = menu->server;
315
+	pxe_type = menu->items[menu->selection].type;
316
+
317
+	/* Free boot menu */
318
+	free ( menu );
319
+
320
+	/* Return immediately if local boot selected */
321
+	if ( ! pxe_type )
322
+		return 0;
323
+
324
+	/* Attempt PXE Boot Server Discovery */
325
+	if ( ( rc = pxebs ( netdev, pxe_server, pxe_type ) ) != 0 )
326
+		return rc;
327
+
328
+	/* Attempt boot */
329
+	pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME );
330
+	assert ( pxebs_settings );
331
+	fetch_ipv4_setting ( pxebs_settings, &next_server_setting,
332
+			     &next_server );
333
+	fetch_string_setting ( pxebs_settings, &filename_setting,
334
+			       filename, sizeof ( filename ) );
335
+	return boot_next_server_and_filename ( next_server, filename );
336
+}

Loading…
Cancel
Save