瀏覽代碼

[dhcp] Keep multiple DHCP offers received, and use them intelligently

Instead of keeping only the best IP and PXE offers, store all of them,
and pick the best to use just before a request is sent. This allows
priority differentiation to work even when lower-priority offers
provide PXE options, and improves robustness at sites with broken PXE
servers intermingled with working ones: when a ProxyDHCP request times
out, instead of giving up, we try the next PXE offer we've received.
It also allows us to avoid breaking up combined IP+PXE offers, which
can be important with some firewall configurations. This behavior
matches that of most vendor PXE ROMs.

Store a reference to the DHCPOFFER packet in the offer structure, so
that when registering settings after a successful ACK we can register
the proxy PXE settings we originally received; this removes the need
for a nonstandard duplicate REQUEST/ACK to port 67 of proxy servers
like dnsmasq that provide PXE options in the OFFER.

Total cost: 450 bytes uncompressed.

Signed-off-by: Marty Connor <mdc@etherboot.org>
tags/v1.0.0-rc1
Joshua Oreman 15 年之前
父節點
當前提交
5efc2fcb60
共有 1 個文件被更改,包括 228 次插入86 次删除
  1. 228
    86
      src/net/udp/dhcp.c

+ 228
- 86
src/net/udp/dhcp.c 查看文件

@@ -206,6 +206,36 @@ static struct dhcp_session_state dhcp_state_request;
206 206
 static struct dhcp_session_state dhcp_state_proxy;
207 207
 static struct dhcp_session_state dhcp_state_pxebs;
208 208
 
209
+/** DHCP offer is valid for IP lease */
210
+#define DHCP_OFFER_IP	1
211
+
212
+/** DHCP offer is valid for PXE options */
213
+#define DHCP_OFFER_PXE	2
214
+
215
+/** A DHCP offer */
216
+struct dhcp_offer {
217
+	/** IP address of server granting offer */
218
+	struct in_addr server;
219
+
220
+	/** IP address being offered, or 0.0.0.0 for a pure proxy */
221
+	struct in_addr ip;
222
+
223
+	/** DHCP packet containing PXE options; NULL if missing or proxied */
224
+	struct dhcp_packet *pxe;
225
+
226
+	/** Valid uses for this offer, a combination of DHCP_OFFER bits */
227
+	uint8_t valid;
228
+
229
+	/** Priority of this offer */
230
+	int8_t priority;
231
+
232
+	/** Whether to ignore PXE DHCP extensions */
233
+	uint8_t no_pxedhcp;
234
+};
235
+
236
+/** Maximum number of DHCP offers to queue */
237
+#define DHCP_MAX_OFFERS   6
238
+
209 239
 /** A DHCP session */
210 240
 struct dhcp_session {
211 241
 	/** Reference counter */
@@ -222,22 +252,6 @@ struct dhcp_session {
222 252
 	/** State of the session */
223 253
 	struct dhcp_session_state *state;
224 254
 
225
-	/** Offered IP address */
226
-	struct in_addr offer;
227
-	/** DHCP server */
228
-	struct in_addr server;
229
-	/** DHCP offer priority */
230
-	int priority;
231
-
232
-	/** ProxyDHCP protocol extensions should be ignored */
233
-	int no_pxedhcp;
234
-	/** ProxyDHCP server */
235
-	struct in_addr proxy_server;
236
-	/** ProxyDHCP port */
237
-	uint16_t proxy_port;
238
-	/** ProxyDHCP server priority */
239
-	int proxy_priority;
240
-
241 255
 	/** PXE Boot Server type */
242 256
 	uint16_t pxe_type;
243 257
 	/** List of PXE Boot Servers to attempt */
@@ -249,6 +263,11 @@ struct dhcp_session {
249 263
 	struct retry_timer timer;
250 264
 	/** Start time of the current state (in ticks) */
251 265
 	unsigned long start;
266
+
267
+	/** DHCP offer just requested */
268
+	struct dhcp_offer *current_offer;
269
+	/** List of DHCP offers received */
270
+	struct dhcp_offer offers[DHCP_MAX_OFFERS];
252 271
 };
253 272
 
254 273
 /**
@@ -259,6 +278,12 @@ struct dhcp_session {
259 278
 static void dhcp_free ( struct refcnt *refcnt ) {
260 279
 	struct dhcp_session *dhcp =
261 280
 		container_of ( refcnt, struct dhcp_session, refcnt );
281
+	int i;
282
+
283
+	for ( i = 0 ; i < DHCP_MAX_OFFERS ; i++ ) {
284
+		if ( dhcp->offers[i].pxe )
285
+			dhcppkt_put ( dhcp->offers[i].pxe );
286
+	}
262 287
 
263 288
 	netdev_put ( dhcp->netdev );
264 289
 	free ( dhcp );
@@ -303,6 +328,35 @@ static void dhcp_set_state ( struct dhcp_session *dhcp,
303 328
 	start_timer_nodelay ( &dhcp->timer );
304 329
 }
305 330
 
331
+/**
332
+ * Determine next DHCP offer to try
333
+ *
334
+ * @v dhcp		DHCP session
335
+ * @v type		DHCP offer type
336
+ * @ret offer		Next DHCP offer to try
337
+ *
338
+ * Offers are ranked by priority, then by completeness (combined
339
+ * IP+PXE are tried before @a type alone), then by order of receipt.
340
+ */
341
+static struct dhcp_offer * dhcp_next_offer ( struct dhcp_session *dhcp,
342
+					     uint8_t type ) {
343
+
344
+	struct dhcp_offer *offer;
345
+	struct dhcp_offer *best = NULL;
346
+
347
+	for ( offer = dhcp->offers ; offer < dhcp->offers + DHCP_MAX_OFFERS ;
348
+	      offer++ ) {
349
+		if ( ( offer->valid & type ) &&
350
+		     ( ( best == NULL ) ||
351
+		       ( offer->priority > best->priority ) ||
352
+		       ( ( offer->priority == best->priority ) &&
353
+			 ( offer->valid & ~best->valid ) ) ) )
354
+			best = offer;
355
+	}
356
+
357
+	return best;
358
+}
359
+
306 360
 /****************************************************************************
307 361
  *
308 362
  * DHCP state machine
@@ -330,7 +384,7 @@ static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
330 384
 }
331 385
 
332 386
 /**
333
- * Handle received packet during DHCP discovery
387
+ * Handle received DHCPOFFER during any state
334 388
  *
335 389
  * @v dhcp		DHCP session
336 390
  * @v dhcppkt		DHCP packet
@@ -338,19 +392,17 @@ static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
338 392
  * @v msgtype		DHCP message type
339 393
  * @v server_id		DHCP server ID
340 394
  */
341
-static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
342
-				struct dhcp_packet *dhcppkt,
343
-				struct sockaddr_in *peer, uint8_t msgtype,
344
-				struct in_addr server_id ) {
345
-	struct in_addr ip;
395
+static void dhcp_rx_offer ( struct dhcp_session *dhcp,
396
+			    struct dhcp_packet *dhcppkt,
397
+			    struct sockaddr_in *peer, uint8_t msgtype,
398
+			    struct in_addr server_id ) {
346 399
 	char vci[9]; /* "PXEClient" */
347 400
 	int vci_len;
348 401
 	int has_pxeclient;
349 402
 	int pxeopts_len;
350 403
 	int has_pxeopts;
351
-	int8_t priority = 0;
352
-	uint8_t no_pxedhcp = 0;
353
-	unsigned long elapsed;
404
+	struct dhcp_offer *offer;
405
+	int i;
354 406
 
355 407
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
356 408
 	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
@@ -359,9 +411,27 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
359 411
 		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
360 412
 
361 413
 	/* Identify offered IP address */
362
-	ip = dhcppkt->dhcphdr->yiaddr;
363
-	if ( ip.s_addr )
364
-		DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
414
+	if ( dhcppkt->dhcphdr->yiaddr.s_addr )
415
+		DBGC ( dhcp, " for %s", inet_ntoa ( dhcppkt->dhcphdr->yiaddr ));
416
+
417
+	/* Enqueue an offer to be filled in */
418
+	for ( i = 0 ; i < DHCP_MAX_OFFERS ; i++ ) {
419
+		if ( dhcp->offers[i].server.s_addr == server_id.s_addr ) {
420
+			DBGC ( dhcp, " dup\n" );
421
+			return;
422
+		}
423
+
424
+		if ( ! dhcp->offers[i].valid )
425
+			break;
426
+	}
427
+	if ( i == DHCP_MAX_OFFERS ) {
428
+		DBGC ( dhcp, " dropped\n" );
429
+		return;
430
+	}
431
+
432
+	offer = &dhcp->offers[i];
433
+	offer->server = server_id;
434
+	offer->ip = dhcppkt->dhcphdr->yiaddr;
365 435
 
366 436
 	/* Identify "PXEClient" vendor class */
367 437
 	vci_len = dhcppkt_fetch ( dhcppkt, DHCP_VENDOR_CLASS_ID,
@@ -375,43 +445,53 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
375 445
 	if ( has_pxeclient )
376 446
 		DBGC ( dhcp, "%s", ( has_pxeopts ? " pxe" : " proxy" ) );
377 447
 
448
+	if ( has_pxeclient && has_pxeopts ) {
449
+		/* Save reference to packet for future use */
450
+		if ( offer->pxe )
451
+			dhcppkt_put ( offer->pxe );
452
+		offer->pxe = dhcppkt_get ( dhcppkt );
453
+	}
454
+
378 455
 	/* Identify priority */
379
-	dhcppkt_fetch ( dhcppkt, DHCP_EB_PRIORITY, &priority,
380
-			sizeof ( priority ) );
381
-	if ( priority )
382
-		DBGC ( dhcp, " pri %d", priority );
456
+	dhcppkt_fetch ( dhcppkt, DHCP_EB_PRIORITY, &offer->priority,
457
+			sizeof ( offer->priority ) );
458
+	if ( offer->priority )
459
+		DBGC ( dhcp, " pri %d", offer->priority );
383 460
 
384 461
 	/* Identify ignore-PXE flag */
385
-	dhcppkt_fetch ( dhcppkt, DHCP_EB_NO_PXEDHCP, &no_pxedhcp,
386
-			sizeof ( no_pxedhcp ) );
387
-	if ( no_pxedhcp )
462
+	dhcppkt_fetch ( dhcppkt, DHCP_EB_NO_PXEDHCP, &offer->no_pxedhcp,
463
+			sizeof ( offer->no_pxedhcp ) );
464
+	if ( offer->no_pxedhcp )
388 465
 		DBGC ( dhcp, " nopxe" );
389 466
 	DBGC ( dhcp, "\n" );
390 467
 
391
-	/* Select as DHCP offer, if applicable */
392
-	if ( ip.s_addr && ( peer->sin_port == htons ( BOOTPS_PORT ) ) &&
393
-	     ( ( msgtype == DHCPOFFER ) || ( ! msgtype /* BOOTP */ ) ) &&
394
-	     ( priority >= dhcp->priority ) ) {
395
-		dhcp->offer = ip;
396
-		dhcp->server = server_id;
397
-		dhcp->priority = priority;
398
-		dhcp->no_pxedhcp = no_pxedhcp;
399
-	}
468
+	/* Determine roles this offer can fill */
469
+	if ( offer->ip.s_addr &&
470
+	     ( peer->sin_port == htons ( BOOTPS_PORT ) ) &&
471
+	     ( ( msgtype == DHCPOFFER ) || ( ! msgtype /* BOOTP */ ) ) )
472
+		offer->valid |= DHCP_OFFER_IP;
400 473
 
401
-	/* Select as ProxyDHCP offer, if applicable */
402
-	if ( has_pxeclient && ( msgtype == DHCPOFFER ) &&
403
-	     ( priority >= dhcp->proxy_priority ) ) {
404
-		/* If the offer already includes the PXE options, then
405
-		 * assume that we can send the ProxyDHCPREQUEST to
406
-		 * port 67 (since the DHCPDISCOVER that triggered this
407
-		 * ProxyDHCPOFFER was sent to port 67).  Otherwise,
408
-		 * send the ProxyDHCPREQUEST to port 4011.
409
-		 */
410
-		dhcp->proxy_server = server_id;
411
-		dhcp->proxy_port = ( has_pxeopts ? htons ( BOOTPS_PORT )
412
-				     : htons ( PXE_PORT ) );
413
-		dhcp->proxy_priority = priority;
414
-	}
474
+	if ( has_pxeclient && ( msgtype == DHCPOFFER ) )
475
+		offer->valid |= DHCP_OFFER_PXE;
476
+}
477
+
478
+/**
479
+ * Handle received packet during DHCP discovery
480
+ *
481
+ * @v dhcp		DHCP session
482
+ * @v dhcppkt		DHCP packet
483
+ * @v peer		DHCP server address
484
+ * @v msgtype		DHCP message type
485
+ * @v server_id		DHCP server ID
486
+ */
487
+static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
488
+				struct dhcp_packet *dhcppkt,
489
+				struct sockaddr_in *peer, uint8_t msgtype,
490
+				struct in_addr server_id ) {
491
+	unsigned long elapsed;
492
+	struct dhcp_offer *ip_offer;
493
+
494
+	dhcp_rx_offer ( dhcp, dhcppkt, peer, msgtype, server_id );
415 495
 
416 496
 	/* We can exit the discovery state when we have a valid
417 497
 	 * DHCPOFFER, and either:
@@ -422,12 +502,14 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
422 502
 	 */
423 503
 
424 504
 	/* If we don't yet have a DHCPOFFER, do nothing */
425
-	if ( ! dhcp->offer.s_addr )
505
+	ip_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_IP );
506
+	if ( ! ip_offer )
426 507
 		return;
427 508
 
428 509
 	/* If we can't yet transition to DHCPREQUEST, do nothing */
429 510
 	elapsed = ( currticks() - dhcp->start );
430
-	if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_server.s_addr ||
511
+	if ( ! ( ip_offer->no_pxedhcp ||
512
+		 dhcp_next_offer ( dhcp, DHCP_OFFER_PXE ) ||
431 513
 		 ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) )
432 514
 		return;
433 515
 
@@ -444,7 +526,8 @@ static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) {
444 526
 	unsigned long elapsed = ( currticks() - dhcp->start );
445 527
 
446 528
 	/* Give up waiting for ProxyDHCP before we reach the failure point */
447
-	if ( dhcp->offer.s_addr && ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) {
529
+	if ( dhcp_next_offer ( dhcp, DHCP_OFFER_IP ) &&
530
+	     ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) {
448 531
 		dhcp_set_state ( dhcp, &dhcp_state_request );
449 532
 		return;
450 533
 	}
@@ -474,21 +557,23 @@ static int dhcp_request_tx ( struct dhcp_session *dhcp,
474 557
 			     struct dhcp_packet *dhcppkt,
475 558
 			     struct sockaddr_in *peer ) {
476 559
 	int rc;
560
+	struct dhcp_offer *offer;
561
+
562
+	offer = dhcp->current_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_IP );
477 563
 
478 564
 	DBGC ( dhcp, "DHCP %p DHCPREQUEST to %s:%d",
479
-	       dhcp, inet_ntoa ( dhcp->server ), BOOTPS_PORT );
480
-	DBGC ( dhcp, " for %s\n", inet_ntoa ( dhcp->offer ) );
565
+	       dhcp, inet_ntoa ( offer->server ), BOOTPS_PORT );
566
+	DBGC ( dhcp, " for %s\n", inet_ntoa ( offer->ip ) );
481 567
 
482 568
 	/* Set server ID */
483 569
 	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
484
-				    &dhcp->server,
485
-				    sizeof ( dhcp->server ) ) ) != 0 )
570
+				    &offer->server,
571
+				    sizeof ( offer->server ) ) ) != 0 )
486 572
 		return rc;
487 573
 
488 574
 	/* Set requested IP address */
489 575
 	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS,
490
-				    &dhcp->offer,
491
-				    sizeof ( dhcp->offer ) ) ) != 0 )
576
+				    &offer->ip, sizeof ( offer->ip ) ) ) != 0 )
492 577
 		return rc;
493 578
 
494 579
 	/* Set server address */
@@ -514,6 +599,18 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
514 599
 	struct in_addr ip;
515 600
 	struct settings *parent;
516 601
 	int rc;
602
+	struct dhcp_offer *pxe_offer;
603
+
604
+	if ( msgtype == DHCPOFFER ) {
605
+		dhcp_rx_offer ( dhcp, dhcppkt, peer, msgtype, server_id );
606
+		if ( dhcp_next_offer ( dhcp, DHCP_OFFER_IP ) !=
607
+		     dhcp->current_offer ) {
608
+			/* Restart due to higher-priority offer received */
609
+			DBGC ( dhcp, "DHCP %p re-requesting\n", dhcp );
610
+			dhcp_set_state ( dhcp, &dhcp_state_request );
611
+		}
612
+		return;
613
+	}
517 614
 
518 615
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
519 616
 	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
@@ -532,7 +629,7 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
532 629
 		return;
533 630
 	if ( msgtype /* BOOTP */ && ( msgtype != DHCPACK ) )
534 631
 		return;
535
-	if ( server_id.s_addr != dhcp->server.s_addr )
632
+	if ( server_id.s_addr != dhcp->current_offer->server.s_addr )
536 633
 		return;
537 634
 
538 635
 	/* Record assigned address */
@@ -547,18 +644,31 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
547 644
 		return;
548 645
 	}
549 646
 
550
-	/* Start ProxyDHCPREQUEST if applicable */
551
-	if ( dhcp->proxy_server.s_addr /* Have ProxyDHCP server */ &&
552
-	     ( ! dhcp->no_pxedhcp ) /* ProxyDHCP not disabled */ &&
553
-	     ( /* ProxyDHCP server is not just the DHCP server itself */
554
-	       ( dhcp->proxy_server.s_addr != dhcp->server.s_addr ) ||
555
-	       ( dhcp->proxy_port != htons ( BOOTPS_PORT ) ) ) ) {
647
+	/* Locate best source of PXE settings */
648
+	pxe_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_PXE );
649
+
650
+	if ( ( ! pxe_offer ) || /* No PXE available */
651
+	     /* IP offer instructs us to ignore PXE */
652
+	     dhcp->current_offer->no_pxedhcp ||
653
+	     /* PXE settings already registered with IP offer */
654
+	     ( ( dhcp->current_offer == pxe_offer ) && ( pxe_offer->pxe ) ) ) {
655
+
656
+		/* Terminate DHCP */
657
+		dhcp_finished ( dhcp, 0 );
658
+
659
+	} else if ( pxe_offer->pxe ) {
660
+		/* Register PXE settings and terminate DHCP */
661
+		pxe_offer->pxe->settings.name = PROXYDHCP_SETTINGS_NAME;
662
+		if ( ( rc = register_settings ( &pxe_offer->pxe->settings,
663
+						NULL ) ) != 0 ) {
664
+			DBGC ( dhcp, "DHCP %p could not register settings: "
665
+			       "%s\n", dhcp, strerror ( rc ) );
666
+		}
667
+		dhcp_finished ( dhcp, rc );
668
+	} else {
669
+		/* Start ProxyDHCP */
556 670
 		dhcp_set_state ( dhcp, &dhcp_state_proxy );
557
-		return;
558 671
 	}
559
-
560
-	/* Terminate DHCP */
561
-	dhcp_finished ( dhcp, 0 );
562 672
 }
563 673
 
564 674
 /**
@@ -593,19 +703,22 @@ static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
593 703
 			   struct dhcp_packet *dhcppkt,
594 704
 			   struct sockaddr_in *peer ) {
595 705
 	int rc;
706
+	struct dhcp_offer *offer;
707
+
708
+	offer = dhcp->current_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_PXE );
596 709
 
597 710
 	DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s:%d\n", dhcp,
598
-	       inet_ntoa ( dhcp->proxy_server ), ntohs ( dhcp->proxy_port ) );
711
+	       inet_ntoa ( offer->server ), PXE_PORT );
599 712
 
600 713
 	/* Set server ID */
601 714
 	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
602
-				    &dhcp->proxy_server,
603
-				    sizeof ( dhcp->proxy_server ) ) ) != 0 )
715
+				    &offer->server,
716
+				    sizeof ( offer->server ) ) )  != 0 )
604 717
 		return rc;
605 718
 
606 719
 	/* Set server address */
607
-	peer->sin_addr = dhcp->proxy_server;
608
-	peer->sin_port = dhcp->proxy_port;
720
+	peer->sin_addr = offer->server;
721
+	peer->sin_port = htons ( PXE_PORT );
609 722
 
610 723
 	return 0;
611 724
 }
@@ -625,6 +738,13 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
625 738
 			    struct in_addr server_id ) {
626 739
 	int rc;
627 740
 
741
+	/* Enqueue last-minute DHCPOFFERs for use in case of failure */
742
+	if ( peer->sin_port == htons ( BOOTPS_PORT ) &&
743
+	     msgtype == DHCPOFFER ) {
744
+		dhcp_rx_offer ( dhcp, dhcppkt, peer, msgtype, server_id );
745
+		return;
746
+	}
747
+
628 748
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
629 749
 	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
630 750
 	       ntohs ( peer->sin_port ) );
@@ -633,12 +753,12 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
633 753
 	DBGC ( dhcp, "\n" );
634 754
 
635 755
 	/* Filter out unacceptable responses */
636
-	if ( peer->sin_port != dhcp->proxy_port )
756
+	if ( peer->sin_port != htons ( PXE_PORT ) )
637 757
 		return;
638
-	if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) )
758
+	if ( msgtype != DHCPACK && msgtype != DHCPOFFER )
639 759
 		return;
640 760
 	if ( server_id.s_addr /* Linux PXE server omits server ID */ &&
641
-	     ( server_id.s_addr != dhcp->proxy_server.s_addr ) )
761
+	     ( server_id.s_addr != dhcp->current_offer->server.s_addr ) )
642 762
 		return;
643 763
 
644 764
 	/* Register settings */
@@ -664,6 +784,28 @@ static void dhcp_proxy_expired ( struct dhcp_session *dhcp ) {
664 784
 
665 785
 	/* Give up waiting for ProxyDHCP before we reach the failure point */
666 786
 	if ( elapsed > PROXYDHCP_MAX_TIMEOUT ) {
787
+
788
+		/* Mark failed offer as unsuitable for ProxyDHCP */
789
+		dhcp->current_offer->valid &= ~DHCP_OFFER_PXE;
790
+
791
+		/* Prefer not to use only half of a PXE+IP offer if we
792
+		 * have other offers available
793
+		 */
794
+		dhcp->current_offer->priority = -1;
795
+
796
+		/* If we have any other PXE offers we can try, go back
797
+		 * to DHCPREQUEST (since they might not be proxied
798
+		 * offers, or might be coupled to a new IP address).
799
+		 * We should probably DHCPRELEASE our old IP, but the
800
+		 * standard does not require it.
801
+		 */
802
+		if ( dhcp_next_offer ( dhcp, DHCP_OFFER_PXE ) ) {
803
+			dhcp->local.sin_addr.s_addr = 0;
804
+			dhcp_set_state ( dhcp, &dhcp_state_request );
805
+			return;
806
+		}
807
+
808
+		/* No possibilities left; finish without PXE options */
667 809
 		dhcp_finished ( dhcp, 0 );
668 810
 		return;
669 811
 	}

Loading…
取消
儲存