Browse Source

[DHCP] Fix up fake-packet creation as used by PXENV_GET_CACHED_INFO

Add dedicated functions create_dhcpdiscover(), create_dhcpack() and
create_proxydhcpack() for use by external code such as the PXE preboot
code.

Register ProxyDHCP options under the global scope "proxydhcp".

Unregister previously-acquired DHCP and ProxyDHCP settings when DHCP
succeeds.
tags/v0.9.4
Michael Brown 17 years ago
parent
commit
ee4206a8a7
5 changed files with 148 additions and 79 deletions
  1. 2
    4
      src/arch/i386/image/nbi.c
  2. 5
    7
      src/include/gpxe/dhcp.h
  3. 34
    25
      src/interface/pxe/pxe_preboot.c
  4. 107
    37
      src/net/udp/dhcp.c
  5. 0
    6
      src/usr/dhcpmgmt.c

+ 2
- 4
src/arch/i386/image/nbi.c View File

@@ -390,7 +390,6 @@ static struct net_device * guess_boot_netdev ( void ) {
390 390
  * @ret rc		Return status code
391 391
  */
392 392
 static int nbi_prepare_dhcp ( struct image *image ) {
393
-	struct dhcp_packet dhcppkt;
394 393
 	struct net_device *boot_netdev;
395 394
 	int rc;
396 395
 
@@ -401,9 +400,8 @@ static int nbi_prepare_dhcp ( struct image *image ) {
401 400
 		return -ENODEV;
402 401
 	}
403 402
 
404
-	if ( ( rc = create_dhcp_response ( &dhcppkt, boot_netdev, DHCPACK,
405
-					   NULL, basemem_packet,
406
-					   sizeof ( basemem_packet ) ) ) != 0){
403
+	if ( ( rc = create_dhcpack ( boot_netdev, basemem_packet,
404
+				     sizeof ( basemem_packet ) ) ) != 0 ) {
407 405
 		DBGC ( image, "NBI %p failed to build DHCP packet\n", image );
408 406
 		return rc;
409 407
 	}

+ 5
- 7
src/include/gpxe/dhcp.h View File

@@ -445,14 +445,12 @@ struct dhcphdr {
445 445
 /** Maximum time that we will wait for ProxyDHCP offers */
446 446
 #define PROXYDHCP_WAIT_TIME ( TICKS_PER_SEC * 1 )
447 447
 
448
-extern int create_dhcp_request ( struct dhcp_packet *dhcppkt,
449
-				 struct net_device *netdev, int msgtype,
450
-				 struct settings *offer_settings,
448
+extern int create_dhcpdiscover ( struct net_device *netdev,
449
+				 void *data, size_t max_len );
450
+extern int create_dhcpack ( struct net_device *netdev,
451
+			    void *data, size_t max_len );
452
+extern int create_proxydhcpack ( struct net_device *netdev,
451 453
 				 void *data, size_t max_len );
452
-extern int create_dhcp_response ( struct dhcp_packet *dhcppkt,
453
-				  struct net_device *netdev, int msgtype,
454
-				  struct settings *settings,
455
-				  void *data, size_t max_len );
456 454
 extern int start_dhcp ( struct job_interface *job, struct net_device *netdev );
457 455
 
458 456
 #endif /* _GPXE_DHCP_H */

+ 34
- 25
src/interface/pxe/pxe_preboot.c View File

@@ -65,6 +65,26 @@ union pxe_cached_info {
65 65
 	BOOTPLAYER_t packet;
66 66
 } __attribute__ (( packed ));
67 67
 
68
+/** A PXE DHCP packet creator */
69
+struct pxe_dhcp_packet_creator {
70
+	/** Create DHCP packet
71
+	 *
72
+	 * @v netdev		Network device
73
+	 * @v data		Buffer for DHCP packet
74
+	 * @v max_len		Size of DHCP packet buffer
75
+	 * @ret rc		Return status code
76
+	 */
77
+	int ( * create ) ( struct net_device *netdev, void *data,
78
+			   size_t max_len );
79
+};
80
+
81
+/** PXE DHCP packet creators */
82
+static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = {
83
+	[CACHED_INFO_DHCPDISCOVER] = { create_dhcpdiscover },
84
+	[CACHED_INFO_DHCPACK] = { create_dhcpack },
85
+	[CACHED_INFO_BINL] = { create_proxydhcpack },
86
+};
87
+
68 88
 /* The case in which the caller doesn't supply a buffer is really
69 89
  * awkward to support given that we have multiple sources of options,
70 90
  * and that we don't actually store the DHCP packets.  (We may not
@@ -117,13 +137,9 @@ PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
117 137
  */
118 138
 PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
119 139
 				     *get_cached_info ) {
120
-	struct dhcp_packet dhcppkt;
121
-	int ( * dhcp_packet_creator ) ( struct dhcp_packet *dhcppkt,
122
-					struct net_device *netdev, int msgtype,
123
-					struct settings *settings,
124
-					void *data, size_t max_len );
140
+	struct pxe_dhcp_packet_creator *creator;
141
+	union pxe_cached_info *info;
125 142
 	unsigned int idx;
126
-	unsigned int msgtype;
127 143
 	size_t len;
128 144
 	userptr_t buffer;
129 145
 	int rc;
@@ -135,25 +151,18 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
135 151
 
136 152
 	/* Sanity check */
137 153
         idx = ( get_cached_info->PacketType - 1 );
138
-	if ( idx >= ( sizeof ( cached_info ) / sizeof ( cached_info[0] ) ) ) {
154
+	if ( idx >= NUM_CACHED_INFOS ) {
139 155
 		DBG ( " bad PacketType" );
140 156
 		goto err;
141 157
 	}
158
+	info = &cached_info[idx];
142 159
 
143 160
 	/* Construct cached version of packet, if not already constructed. */
144
-	if ( ! cached_info[idx].dhcphdr.op ) {
161
+	if ( ! info->dhcphdr.op ) {
145 162
 		/* Construct DHCP packet */
146
-		if ( get_cached_info->PacketType ==
147
-		     PXENV_PACKET_TYPE_DHCP_DISCOVER ) {
148
-			dhcp_packet_creator = create_dhcp_request;
149
-			msgtype = DHCPDISCOVER;
150
-		} else {
151
-			dhcp_packet_creator = create_dhcp_response;
152
-			msgtype = DHCPACK;
153
-		}
154
-		if ( ( rc = dhcp_packet_creator ( &dhcppkt, pxe_netdev,
155
-				       msgtype, NULL, &cached_info[idx],
156
-				       sizeof ( cached_info[idx] ) ) ) != 0 ) {
163
+		creator = &pxe_dhcp_packet_creators[idx];
164
+		if ( ( rc = creator->create ( pxe_netdev, info,
165
+					      sizeof ( *info ) ) ) != 0 ) {
157 166
 			DBG ( " failed to build packet" );
158 167
 			goto err;
159 168
 		}
@@ -188,8 +197,8 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
188 197
 		 */
189 198
 		get_cached_info->Buffer.segment = rm_ds;
190 199
 		get_cached_info->Buffer.offset =
191
-			( unsigned ) ( & __from_data16 ( cached_info[idx] ) );
192
-		get_cached_info->BufferSize = sizeof ( cached_info[idx] );
200
+			( unsigned ) ( __from_data16 ( info ) );
201
+		get_cached_info->BufferSize = sizeof ( *info );
193 202
 		DBG ( " returning %04x:%04x+%04x['%x']",
194 203
 		      get_cached_info->Buffer.segment,
195 204
 		      get_cached_info->Buffer.offset,
@@ -197,13 +206,13 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
197 206
 		      get_cached_info->BufferLimit );
198 207
 	} else {
199 208
 		/* Copy packet to client buffer */
200
-		if ( len > sizeof ( cached_info[idx] ) )
201
-			len = sizeof ( cached_info[idx] );
202
-		if ( len < sizeof ( cached_info[idx] ) )
209
+		if ( len > sizeof ( *info ) )
210
+			len = sizeof ( *info );
211
+		if ( len < sizeof ( *info ) )
203 212
 			DBG ( " buffer may be too short" );
204 213
 		buffer = real_to_user ( get_cached_info->Buffer.segment,
205 214
 					get_cached_info->Buffer.offset );
206
-		copy_to_user ( buffer, 0, &cached_info[idx], len );
215
+		copy_to_user ( buffer, 0, info, len );
207 216
 		get_cached_info->BufferSize = len;
208 217
 	}
209 218
 

+ 107
- 37
src/net/udp/dhcp.c View File

@@ -130,6 +130,9 @@ static uint32_t dhcp_xid ( struct net_device *netdev ) {
130 130
 	return xid;
131 131
 }
132 132
 
133
+/** Settings block name used for ProxyDHCP responses */
134
+#define PROXYDHCP_SETTINGS_NAME "proxydhcp"
135
+
133 136
 /**
134 137
  * Create a DHCP packet
135 138
  *
@@ -145,10 +148,10 @@ static uint32_t dhcp_xid ( struct net_device *netdev ) {
145 148
  * dhcp_packet structure that can be passed to
146 149
  * set_dhcp_packet_option() or copy_dhcp_packet_options().
147 150
  */
148
-static int create_dhcp_packet ( struct dhcp_packet *dhcppkt,
149
-				struct net_device *netdev, uint8_t msgtype,
150
-				struct dhcp_options *options, 
151
-				void *data, size_t max_len ) {
151
+int create_dhcp_packet ( struct dhcp_packet *dhcppkt,
152
+			 struct net_device *netdev, uint8_t msgtype,
153
+			 struct dhcp_options *options, 
154
+			 void *data, size_t max_len ) {
152 155
 	struct dhcphdr *dhcphdr = data;
153 156
 	size_t options_len;
154 157
 	unsigned int hlen;
@@ -160,10 +163,6 @@ static int create_dhcp_packet ( struct dhcp_packet *dhcppkt,
160 163
 		return -ENOSPC;
161 164
 
162 165
 	/* Initialise DHCP packet content */
163
-
164
-        /* FIXME: wrong place to fix this. */
165
-        memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
166
-
167 166
 	memset ( dhcphdr, 0, max_len );
168 167
 	dhcphdr->xid = dhcp_xid ( netdev );
169 168
 	dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
@@ -182,6 +181,7 @@ static int create_dhcp_packet ( struct dhcp_packet *dhcppkt,
182 181
 	memcpy ( dhcphdr->options, options->data, options_len );
183 182
 
184 183
 	/* Initialise DHCP packet structure and settings interface */
184
+	memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
185 185
 	dhcppkt_init ( dhcppkt, NULL, data, max_len );
186 186
 	
187 187
 	/* Set DHCP_MESSAGE_TYPE option */
@@ -221,29 +221,30 @@ struct dhcp_client_uuid {
221 221
 #define DHCP_CLIENT_UUID_TYPE 0
222 222
 
223 223
 /**
224
- * Create DHCP request
224
+ * Create DHCP request packet
225 225
  *
226 226
  * @v dhcppkt		DHCP packet structure to fill in
227 227
  * @v netdev		Network device
228
- * @v msgtype		DHCP message type
229
- * @v offer_settings	Settings received in DHCPOFFER, or NULL
228
+ * @v dhcpoffer		DHCPOFFER packet received from server
230 229
  * @v data		Buffer for DHCP packet
231 230
  * @v max_len		Size of DHCP packet buffer
232 231
  * @ret rc		Return status code
233 232
  */
234
-int create_dhcp_request ( struct dhcp_packet *dhcppkt,
235
-			  struct net_device *netdev, int msgtype,
236
-			  struct settings *offer_settings,
237
-			  void *data, size_t max_len ) {
233
+static int create_dhcp_request ( struct dhcp_packet *dhcppkt,
234
+				 struct net_device *netdev,
235
+				 struct dhcp_packet *dhcpoffer,
236
+				 void *data, size_t max_len ) {
238 237
 	struct device_description *desc = &netdev->dev->desc;
239 238
 	struct dhcp_netdev_desc dhcp_desc;
240 239
 	struct dhcp_client_id client_id;
241 240
 	struct dhcp_client_uuid client_uuid;
241
+	unsigned int msgtype;
242 242
 	size_t dhcp_features_len;
243 243
 	size_t ll_addr_len;
244 244
 	int rc;
245 245
 
246 246
 	/* Create DHCP packet */
247
+	msgtype = ( dhcpoffer ? DHCPREQUEST : DHCPDISCOVER );
247 248
 	if ( ( rc = create_dhcp_packet ( dhcppkt, netdev, msgtype,
248 249
 					 &dhcp_request_options, data,
249 250
 					 max_len ) ) != 0 ) {
@@ -253,10 +254,10 @@ int create_dhcp_request ( struct dhcp_packet *dhcppkt,
253 254
 	}
254 255
 
255 256
 	/* Copy any required options from previous server repsonse */
256
-	if ( offer_settings ) {
257
+	if ( dhcpoffer ) {
257 258
 		if ( ( rc = copy_setting ( &dhcppkt->settings,
258 259
 					   DHCP_SERVER_IDENTIFIER,
259
-					   offer_settings,
260
+					   &dhcpoffer->settings,
260 261
 					   DHCP_SERVER_IDENTIFIER ) ) != 0 ) {
261 262
 			DBG ( "DHCP could not set server identifier "
262 263
 			      "option: %s\n", strerror ( rc ) );
@@ -264,7 +265,7 @@ int create_dhcp_request ( struct dhcp_packet *dhcppkt,
264 265
 		}
265 266
 		if ( ( rc = copy_setting ( &dhcppkt->settings,
266 267
 					   DHCP_REQUESTED_ADDRESS,
267
-					   offer_settings,
268
+					   &dhcpoffer->settings,
268 269
 					   DHCP_EB_YIADDR ) ) != 0 ) {
269 270
 			DBG ( "DHCP could not set requested address "
270 271
 			      "option: %s\n", strerror ( rc ) );
@@ -322,27 +323,87 @@ int create_dhcp_request ( struct dhcp_packet *dhcppkt,
322 323
 }
323 324
 
324 325
 /**
325
- * Create DHCP response
326
+ * Create DHCPDISCOVER packet
327
+ *
328
+ * @v netdev		Network device
329
+ * @v data		Buffer for DHCP packet
330
+ * @v max_len		Size of DHCP packet buffer
331
+ * @ret rc		Return status code
332
+ *
333
+ * Used by external code.
334
+ */
335
+int create_dhcpdiscover ( struct net_device *netdev,
336
+			  void *data, size_t max_len ) {
337
+	struct dhcp_packet dhcppkt;
338
+
339
+	return create_dhcp_request ( &dhcppkt, netdev, NULL, data, max_len );
340
+}
341
+
342
+/**
343
+ * Create DHCPACK packet
344
+ *
345
+ * @v netdev		Network device
346
+ * @v data		Buffer for DHCP packet
347
+ * @v max_len		Size of DHCP packet buffer
348
+ * @ret rc		Return status code
349
+ *
350
+ * Used by external code.
351
+ */
352
+int create_dhcpack ( struct net_device *netdev,
353
+		     void *data, size_t max_len ) {
354
+	struct dhcp_packet dhcppkt;
355
+	int rc;
356
+
357
+	/* Create base DHCPACK packet */
358
+	if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL,
359
+					 data, max_len ) ) != 0 )
360
+		return rc;
361
+
362
+	/* Merge in globally-scoped settings, then netdev-specific
363
+	 * settings.  Do it in this order so that netdev-specific
364
+	 * settings take precedence regardless of stated priorities.
365
+	 */
366
+	if ( ( rc = copy_settings ( &dhcppkt.settings, NULL ) ) != 0 )
367
+		return rc;
368
+	if ( ( rc = copy_settings ( &dhcppkt.settings,
369
+				    netdev_settings ( netdev ) ) ) != 0 )
370
+		return rc;
371
+
372
+	return 0;
373
+}
374
+
375
+/**
376
+ * Create ProxyDHCPACK packet
326 377
  *
327
- * @v dhcppkt		DHCP packet structure to fill in
328 378
  * @v netdev		Network device
329
- * @v msgtype		DHCP message type
330
- * @v settings		Settings to include, or NULL
331 379
  * @v data		Buffer for DHCP packet
332 380
  * @v max_len		Size of DHCP packet buffer
333 381
  * @ret rc		Return status code
382
+ *
383
+ * Used by external code.
334 384
  */
335
-int create_dhcp_response ( struct dhcp_packet *dhcppkt,
336
-			   struct net_device *netdev, int msgtype,
337
-			   struct settings *settings,
338
-			   void *data, size_t max_len ) {
385
+int create_proxydhcpack ( struct net_device *netdev,
386
+			  void *data, size_t max_len ) {
387
+	struct dhcp_packet dhcppkt;
388
+	struct settings *settings;
339 389
 	int rc;
340 390
 
341
-	/* Create packet and copy in options */
342
-	if ( ( rc = create_dhcp_packet ( dhcppkt, netdev, msgtype, NULL,
391
+	/* Identify ProxyDHCP settings */
392
+	settings = find_settings ( PROXYDHCP_SETTINGS_NAME );
393
+
394
+	/* No ProxyDHCP settings => return empty block */
395
+	if ( ! settings ) {
396
+		memset ( data, 0, max_len );
397
+		return 0;
398
+	}
399
+
400
+	/* Create base DHCPACK packet */
401
+	if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL,
343 402
 					 data, max_len ) ) != 0 )
344 403
 		return rc;
345
-	if ( ( rc = copy_settings ( &dhcppkt->settings, settings ) ) != 0 )
404
+
405
+	/* Merge in ProxyDHCP options */
406
+	if ( ( rc = copy_settings ( &dhcppkt.settings, settings ) ) != 0 )
346 407
 		return rc;
347 408
 
348 409
 	return 0;
@@ -356,10 +417,10 @@ int create_dhcp_response ( struct dhcp_packet *dhcppkt,
356 417
 
357 418
 /** A DHCP packet contained in an I/O buffer */
358 419
 struct dhcp_iobuf_packet {
359
-	/** Reference counter */
360
-	struct refcnt refcnt;
361 420
 	/** DHCP packet */
362 421
 	struct dhcp_packet dhcppkt;
422
+	/** Reference counter */
423
+	struct refcnt refcnt;
363 424
 	/** Containing I/O buffer */
364 425
 	struct io_buffer *iobuf;
365 426
 };
@@ -480,18 +541,28 @@ static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
480 541
  * @ret rc		Return status code
481 542
  */
482 543
 static int dhcp_register_settings ( struct dhcp_session *dhcp ) {
544
+	struct settings *old_settings;
483 545
 	struct settings *settings;
484 546
 	struct settings *parent;
485 547
 	int rc;
486 548
 
549
+	/* Register ProxyDHCP settings, if present */
487 550
 	if ( dhcp->proxy_response ) {
488 551
 		settings = &dhcp->proxy_response->dhcppkt.settings;
552
+		settings->name = PROXYDHCP_SETTINGS_NAME;
553
+		old_settings = find_settings ( settings->name );
554
+		if ( old_settings )
555
+			unregister_settings ( old_settings );
489 556
 		if ( ( rc = register_settings ( settings, NULL ) ) != 0 )
490 557
 			return rc;
491 558
 	}
492 559
 
493
-	settings = &dhcp->response->dhcppkt.settings;
560
+	/* Register DHCP settings */
494 561
 	parent = netdev_settings ( dhcp->netdev );
562
+	settings = &dhcp->response->dhcppkt.settings;
563
+	old_settings = find_child_settings ( parent, settings->name );
564
+	if ( old_settings )
565
+		unregister_settings ( old_settings );
495 566
 	if ( ( rc = register_settings ( settings, parent ) ) != 0 )
496 567
 		return rc;
497 568
 
@@ -514,8 +585,8 @@ static int dhcp_send_request ( struct dhcp_session *dhcp ) {
514 585
 	struct xfer_metadata meta = {
515 586
 		.netdev = dhcp->netdev,
516 587
 	};
517
-	struct settings *offer_settings = NULL;
518 588
 	struct io_buffer *iobuf;
589
+	struct dhcp_packet *dhcpoffer;
519 590
 	struct dhcp_packet dhcppkt;
520 591
 	int rc;
521 592
 	
@@ -536,10 +607,9 @@ static int dhcp_send_request ( struct dhcp_session *dhcp ) {
536 607
 		return -ENOMEM;
537 608
 
538 609
 	/* Create DHCP packet in temporary buffer */
539
-	if ( dhcp->response )
540
-		offer_settings = &dhcp->response->dhcppkt.settings;
541
-	if ( ( rc = create_dhcp_request ( &dhcppkt, dhcp->netdev, dhcp->state,
542
-					  offer_settings, iobuf->data,
610
+	dhcpoffer = ( dhcp->response ? &dhcp->response->dhcppkt : NULL );
611
+	if ( ( rc = create_dhcp_request ( &dhcppkt, dhcp->netdev,
612
+					  dhcpoffer, iobuf->data,
543 613
 					  iob_tailroom ( iobuf ) ) ) != 0 ) {
544 614
 		DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
545 615
 		       dhcp, strerror ( rc ) );

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

@@ -33,18 +33,12 @@
33 33
  */
34 34
 
35 35
 int dhcp ( struct net_device *netdev ) {
36
-	struct settings *settings;
37 36
 	int rc;
38 37
 
39 38
 	/* Check we can open the interface first */
40 39
 	if ( ( rc = ifopen ( netdev ) ) != 0 )
41 40
 		return rc;
42 41
 
43
-	/* Unregister any option blocks acquired via DHCP */
44
-	settings = find_child_settings ( netdev_settings ( netdev ), "dhcp" );
45
-	if ( settings )
46
-		unregister_settings ( settings );
47
-
48 42
 	/* Perform DHCP */
49 43
 	printf ( "DHCP (%s %s)", netdev->name, netdev_hwaddr ( netdev ) );
50 44
 	if ( ( rc = start_dhcp ( &monojob, netdev ) ) == 0 )

Loading…
Cancel
Save