Sfoglia il codice sorgente

[dhcp] Omit ProxyDHCPREQUEST if PXE options are present in ProxyDHCPOFFER

Some ProxyDHCP implementations seem to violate the PXE specification
by expecting the client to retain options from the ProxyDHCPOFFER
rather than issuing a separate ProxyDHCPREQUEST.

Work around such broken clients by retaining the ProxyDHCPOFFER
packet, and proceeding to a ProxyDHCPREQUEST only if the
ProxyDHCPOFFER does not already contain PXE options.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 anni fa
parent
commit
831106a875
1 ha cambiato i file con 67 aggiunte e 37 eliminazioni
  1. 67
    37
      src/net/udp/dhcp.c

+ 67
- 37
src/net/udp/dhcp.c Vedi File

@@ -231,9 +231,9 @@ struct dhcp_session {
231 231
 	int no_pxedhcp;
232 232
 	/** ProxyDHCP server */
233 233
 	struct in_addr proxy_server;
234
-	/** ProxyDHCP port */
235
-	uint16_t proxy_port;
236
-	/** ProxyDHCP server priority */
234
+	/** ProxyDHCP offer */
235
+	struct dhcp_packet *proxy_offer;
236
+	/** ProxyDHCP offer priority */
237 237
 	int proxy_priority;
238 238
 
239 239
 	/** PXE Boot Server type */
@@ -259,6 +259,7 @@ static void dhcp_free ( struct refcnt *refcnt ) {
259 259
 		container_of ( refcnt, struct dhcp_session, refcnt );
260 260
 
261 261
 	netdev_put ( dhcp->netdev );
262
+	dhcppkt_put ( dhcp->proxy_offer );
262 263
 	free ( dhcp );
263 264
 }
264 265
 
@@ -297,6 +298,28 @@ static void dhcp_set_state ( struct dhcp_session *dhcp,
297 298
 	start_timer_nodelay ( &dhcp->timer );
298 299
 }
299 300
 
301
+/**
302
+ * Check if DHCP packet contains PXE options
303
+ *
304
+ * @v dhcppkt		DHCP packet
305
+ * @ret has_pxeopts	DHCP packet contains PXE options
306
+ *
307
+ * It is assumed that the packet is already known to contain option 60
308
+ * set to "PXEClient".
309
+ */
310
+static int dhcp_has_pxeopts ( struct dhcp_packet *dhcppkt ) {
311
+
312
+	/* Check for a boot filename */
313
+	if ( dhcppkt_fetch ( dhcppkt, DHCP_BOOTFILE_NAME, NULL, 0 ) > 0 )
314
+		return 1;
315
+
316
+	/* Check for a PXE boot menu */
317
+	if ( dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 ) > 0 )
318
+		return 1;
319
+
320
+	return 0;
321
+}
322
+
300 323
 /****************************************************************************
301 324
  *
302 325
  * DHCP state machine
@@ -340,8 +363,6 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
340 363
 	char vci[9]; /* "PXEClient" */
341 364
 	int vci_len;
342 365
 	int has_pxeclient;
343
-	int pxeopts_len;
344
-	int has_pxeopts;
345 366
 	int8_t priority = 0;
346 367
 	uint8_t no_pxedhcp = 0;
347 368
 	unsigned long elapsed;
@@ -362,12 +383,10 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
362 383
 				  vci, sizeof ( vci ) );
363 384
 	has_pxeclient = ( ( vci_len >= ( int ) sizeof ( vci ) ) &&
364 385
 			  ( strncmp ( "PXEClient", vci, sizeof (vci) ) == 0 ));
365
-
366
-	/* Identify presence of PXE-specific options */
367
-	pxeopts_len = dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 );
368
-	has_pxeopts = ( pxeopts_len >= 0 );
369
-	if ( has_pxeclient )
370
-		DBGC ( dhcp, "%s", ( has_pxeopts ? " pxe" : " proxy" ) );
386
+	if ( has_pxeclient ) {
387
+		DBGC ( dhcp, "%s",
388
+		       ( dhcp_has_pxeopts ( dhcppkt ) ? " pxe" : " proxy" ) );
389
+	}
371 390
 
372 391
 	/* Identify priority */
373 392
 	dhcppkt_fetch ( dhcppkt, DHCP_EB_PRIORITY, &priority,
@@ -393,17 +412,11 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
393 412
 	}
394 413
 
395 414
 	/* Select as ProxyDHCP offer, if applicable */
396
-	if ( has_pxeclient && ( msgtype == DHCPOFFER ) &&
415
+	if ( server_id.s_addr && has_pxeclient &&
397 416
 	     ( priority >= dhcp->proxy_priority ) ) {
398
-		/* If the offer already includes the PXE options, then
399
-		 * assume that we can send the ProxyDHCPREQUEST to
400
-		 * port 67 (since the DHCPDISCOVER that triggered this
401
-		 * ProxyDHCPOFFER was sent to port 67).  Otherwise,
402
-		 * send the ProxyDHCPREQUEST to port 4011.
403
-		 */
417
+		dhcppkt_put ( dhcp->proxy_offer );
404 418
 		dhcp->proxy_server = server_id;
405
-		dhcp->proxy_port = ( has_pxeopts ? htons ( BOOTPS_PORT )
406
-				     : htons ( PXE_PORT ) );
419
+		dhcp->proxy_offer = dhcppkt_get ( dhcppkt );
407 420
 		dhcp->proxy_priority = priority;
408 421
 	}
409 422
 
@@ -421,7 +434,7 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
421 434
 
422 435
 	/* If we can't yet transition to DHCPREQUEST, do nothing */
423 436
 	elapsed = ( currticks() - dhcp->start );
424
-	if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_server.s_addr ||
437
+	if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_offer ||
425 438
 		 ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) )
426 439
 		return;
427 440
 
@@ -507,6 +520,7 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
507 520
 			      struct in_addr server_id ) {
508 521
 	struct in_addr ip;
509 522
 	struct settings *parent;
523
+	struct settings *settings;
510 524
 	int rc;
511 525
 
512 526
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
@@ -536,21 +550,36 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
536 550
 
537 551
 	/* Register settings */
538 552
 	parent = netdev_settings ( dhcp->netdev );
539
-	if ( ( rc = register_settings ( &dhcppkt->settings, parent ) ) != 0 ){
553
+	settings = &dhcppkt->settings;
554
+	if ( ( rc = register_settings ( settings, parent ) ) != 0 ) {
540 555
 		DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
541 556
 		       dhcp, strerror ( rc ) );
542 557
 		dhcp_finished ( dhcp, rc );
543 558
 		return;
544 559
 	}
545 560
 
546
-	/* Start ProxyDHCPREQUEST if applicable */
547
-	if ( dhcp->proxy_server.s_addr /* Have ProxyDHCP server */ &&
548
-	     ( ! dhcp->no_pxedhcp ) /* ProxyDHCP not disabled */ &&
549
-	     ( /* ProxyDHCP server is not just the DHCP server itself */
550
-	       ( dhcp->proxy_server.s_addr != dhcp->server.s_addr ) ||
551
-	       ( dhcp->proxy_port != htons ( BOOTPS_PORT ) ) ) ) {
552
-		dhcp_set_state ( dhcp, &dhcp_state_proxy );
553
-		return;
561
+	/* Perform ProxyDHCP if applicable */
562
+	if ( dhcp->proxy_offer /* Have ProxyDHCP offer */ &&
563
+	     ( ! dhcp->no_pxedhcp ) /* ProxyDHCP not disabled */ ) {
564
+		if ( dhcp_has_pxeopts ( dhcp->proxy_offer ) ) {
565
+			/* PXE options already present; register settings
566
+			 * without performing a ProxyDHCPREQUEST
567
+			 */
568
+			settings = &dhcp->proxy_offer->settings;
569
+			settings->name = PROXYDHCP_SETTINGS_NAME;
570
+			if ( ( rc = register_settings ( settings,
571
+							NULL ) ) != 0 ) {
572
+				DBGC ( dhcp, "DHCP %p could not register "
573
+				       "proxy settings: %s\n",
574
+				       dhcp, strerror ( rc ) );
575
+				dhcp_finished ( dhcp, rc );
576
+				return;
577
+			}
578
+		} else {
579
+			/* PXE options not present; use a ProxyDHCPREQUEST */
580
+			dhcp_set_state ( dhcp, &dhcp_state_proxy );
581
+			return;
582
+		}
554 583
 	}
555 584
 
556 585
 	/* Terminate DHCP */
@@ -590,8 +619,8 @@ static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
590 619
 			   struct sockaddr_in *peer ) {
591 620
 	int rc;
592 621
 
593
-	DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s:%d\n", dhcp,
594
-	       inet_ntoa ( dhcp->proxy_server ), ntohs ( dhcp->proxy_port ) );
622
+	DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s\n", dhcp,
623
+	       inet_ntoa ( dhcp->proxy_server ) );
595 624
 
596 625
 	/* Set server ID */
597 626
 	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
@@ -601,7 +630,7 @@ static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
601 630
 
602 631
 	/* Set server address */
603 632
 	peer->sin_addr = dhcp->proxy_server;
604
-	peer->sin_port = dhcp->proxy_port;
633
+	peer->sin_port = htons ( PXE_PORT );
605 634
 
606 635
 	return 0;
607 636
 }
@@ -619,6 +648,7 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
619 648
 			    struct dhcp_packet *dhcppkt,
620 649
 			    struct sockaddr_in *peer, uint8_t msgtype,
621 650
 			    struct in_addr server_id ) {
651
+	struct settings *settings = &dhcppkt->settings;
622 652
 	int rc;
623 653
 
624 654
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
@@ -629,7 +659,7 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
629 659
 	DBGC ( dhcp, "\n" );
630 660
 
631 661
 	/* Filter out unacceptable responses */
632
-	if ( peer->sin_port != dhcp->proxy_port )
662
+	if ( peer->sin_port != ntohs ( PXE_PORT ) )
633 663
 		return;
634 664
 	if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) )
635 665
 		return;
@@ -638,9 +668,9 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
638 668
 		return;
639 669
 
640 670
 	/* Register settings */
641
-	dhcppkt->settings.name = PROXYDHCP_SETTINGS_NAME;
642
-	if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) {
643
-		DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
671
+	settings->name = PROXYDHCP_SETTINGS_NAME;
672
+	if ( ( rc = register_settings ( settings, NULL ) ) != 0 ) {
673
+		DBGC ( dhcp, "DHCP %p could not register proxy settings: %s\n",
644 674
 		       dhcp, strerror ( rc ) );
645 675
 		dhcp_finished ( dhcp, rc );
646 676
 		return;

Loading…
Annulla
Salva