Browse Source

[dhcp] Pass PXE boot menu item to PXE Boot Server

Pick out the first boot menu item from the boot menu (option 43.9) and
pass it to the boot server as the boot menu item (option 43.71).

Also improve DHCP debug messages to include more details of the
packets being transmitted.
tags/v0.9.7
Michael Brown 16 years ago
parent
commit
76d05a4da0
3 changed files with 133 additions and 75 deletions
  1. 11
    2
      src/include/gpxe/dhcp.h
  2. 4
    3
      src/net/fakedhcp.c
  3. 118
    70
      src/net/udp/dhcp.c

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

@@ -17,6 +17,7 @@ struct net_device;
17 17
 struct job_interface;
18 18
 struct dhcp_options;
19 19
 struct dhcp_packet;
20
+struct dhcp_pxe_boot_menu_item;
20 21
 
21 22
 /** BOOTP/DHCP server port */
22 23
 #define BOOTPS_PORT 67
@@ -84,6 +85,12 @@ struct dhcp_packet;
84 85
 /** PXE boot server multicast address */
85 86
 #define DHCP_PXE_BOOT_SERVER_MCAST DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 7 )
86 87
 
88
+/** PXE boot menu */
89
+#define DHCP_PXE_BOOT_MENU DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 9 )
90
+
91
+/** PXE boot menu item */
92
+#define DHCP_PXE_BOOT_MENU_ITEM DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 71 )
93
+
87 94
 /** Requested IP address */
88 95
 #define DHCP_REQUESTED_ADDRESS 50
89 96
 
@@ -492,8 +499,10 @@ extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
492 499
 				void *data, size_t max_len );
493 500
 extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
494 501
 				 struct net_device *netdev,
495
-				 struct in_addr ciaddr,
496
-				 struct dhcp_packet *dhcpoffer,
502
+				 unsigned int msgtype, struct in_addr ciaddr,
503
+				 struct in_addr server,
504
+				 struct in_addr requested_ip,
505
+				 struct dhcp_pxe_boot_menu_item *menu_item,
497 506
 				 void *data, size_t max_len );
498 507
 extern int start_dhcp ( struct job_interface *job, struct net_device *netdev );
499 508
 

+ 4
- 3
src/net/fakedhcp.c View File

@@ -108,11 +108,12 @@ static int copy_settings ( struct dhcp_packet *dest,
108 108
 int create_fakedhcpdiscover ( struct net_device *netdev,
109 109
 			      void *data, size_t max_len ) {
110 110
 	struct dhcp_packet dhcppkt;
111
-	struct in_addr ciaddr = { 0 };
111
+	struct in_addr dummy_addr = { 0 };
112 112
 	int rc;
113 113
 
114
-	if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, ciaddr, NULL, data,
115
-					  max_len ) ) != 0 ) {
114
+	if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER,
115
+					  dummy_addr, dummy_addr, dummy_addr,
116
+					  NULL, data, max_len ) ) != 0 ) {
116 117
 		DBG ( "Could not create DHCPDISCOVER: %s\n",
117 118
 		      strerror ( rc ) );
118 119
 		return rc;

+ 118
- 70
src/net/udp/dhcp.c View File

@@ -125,6 +125,21 @@ struct dhcp_client_uuid {
125 125
 
126 126
 #define DHCP_CLIENT_UUID_TYPE 0
127 127
 
128
+/** DHCP PXE boot menu item */
129
+struct dhcp_pxe_boot_menu_item {
130
+	/** "Type"
131
+	 *
132
+	 * This field actually identifies the specific boot server (or
133
+	 * cluster of boot servers offering identical boot files).
134
+	 */
135
+	uint16_t type;
136
+	/** "Layer"
137
+	 *
138
+	 * Just don't ask.
139
+	 */
140
+	uint16_t layer;
141
+} __attribute__ (( packed ));
142
+
128 143
 /**
129 144
  * Name a DHCP packet type
130 145
  *
@@ -448,27 +463,30 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
448 463
  *
449 464
  * @v dhcppkt		DHCP packet structure to fill in
450 465
  * @v netdev		Network device
451
- * @v ciaddr		Client IP address
452
- * @v offer		DHCP offer, if applicable
466
+ * @v msgtype		DHCP message type
467
+ * @v ciaddr		Client IP address, if applicable
468
+ * @v server		Server identifier, if applicable
469
+ * @v requested_ip	Requested address, if applicable
470
+ * @v menu_item		PXE menu item, if applicable
453 471
  * @v data		Buffer for DHCP packet
454 472
  * @v max_len		Size of DHCP packet buffer
455 473
  * @ret rc		Return status code
456 474
  */
457 475
 int dhcp_create_request ( struct dhcp_packet *dhcppkt,
458
-			  struct net_device *netdev, struct in_addr ciaddr,
459
-			  struct dhcp_packet *offer,
476
+			  struct net_device *netdev, unsigned int msgtype,
477
+			  struct in_addr ciaddr, struct in_addr server,
478
+			  struct in_addr requested_ip,
479
+			  struct dhcp_pxe_boot_menu_item *menu_item,
460 480
 			  void *data, size_t max_len ) {
461 481
 	struct device_description *desc = &netdev->dev->desc;
462 482
 	struct dhcp_netdev_desc dhcp_desc;
463 483
 	struct dhcp_client_id client_id;
464 484
 	struct dhcp_client_uuid client_uuid;
465
-	unsigned int msgtype;
466 485
 	size_t dhcp_features_len;
467 486
 	size_t ll_addr_len;
468 487
 	int rc;
469 488
 
470 489
 	/* Create DHCP packet */
471
-	msgtype = ( offer ? DHCPREQUEST : DHCPDISCOVER );
472 490
 	if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype,
473 491
 					 &dhcp_request_options, data,
474 492
 					 max_len ) ) != 0 ) {
@@ -480,30 +498,23 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
480 498
 	/* Set client IP address */
481 499
 	dhcppkt->dhcphdr->ciaddr = ciaddr;
482 500
 
483
-	/* Copy any required options from previous server repsonse */
484
-	if ( offer ) {
485
-		struct in_addr server = { 0 };
486
-		struct in_addr *ip = &offer->dhcphdr->yiaddr;
487
-
488
-		/* Copy server identifier, if present */
489
-		if ( ( dhcppkt_fetch ( offer, DHCP_SERVER_IDENTIFIER, &server,
490
-				       sizeof ( server ) ) >= 0 ) &&
491
-		     ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
492
-					      &server,
493
-					      sizeof ( server ) ) ) != 0 ) ) {
501
+	/* Set server ID, if present */
502
+	if ( server.s_addr &&
503
+	     ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
504
+				      &server, sizeof ( server ) ) ) != 0 ) ) {
494 505
 			DBG ( "DHCP could not set server ID: %s\n",
495 506
 			      strerror ( rc ) );
496 507
 			return rc;
497
-		}
508
+	}
498 509
 
499
-		/* Copy requested IP address, if present */
500
-		if ( ( ip->s_addr != 0 ) &&
501
-		     ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS,
502
-					      ip, sizeof ( *ip ) ) ) != 0 ) ) {
503
-			DBG ( "DHCP could not set requested address: %s\n",
504
-			      strerror ( rc ) );
505
-			return rc;
506
-		}
510
+	/* Set requested IP address, if present */
511
+	if ( requested_ip.s_addr &&
512
+	     ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS,
513
+				      &requested_ip,
514
+				      sizeof ( requested_ip ) ) ) != 0 ) ) {
515
+		DBG ( "DHCP could not set requested address: %s\n",
516
+		      strerror ( rc ) );
517
+		return rc;
507 518
 	}
508 519
 
509 520
 	/* Add options to identify the feature list */
@@ -553,6 +564,16 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
553 564
 		}
554 565
 	}
555 566
 
567
+	/* Set PXE boot menu item, if present */
568
+	if ( menu_item && menu_item->type &&
569
+	     ( ( rc = dhcppkt_store ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
570
+				      menu_item,
571
+				      sizeof ( *menu_item ) ) ) != 0 ) ) {
572
+		DBG ( "DHCP could not set PXE menu item: %s\n",
573
+		      strerror ( rc ) );
574
+		return rc;
575
+	}
576
+
556 577
 	return 0;
557 578
 }
558 579
 
@@ -563,11 +584,11 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
563 584
  * @ret rc		Return status code
564 585
  */
565 586
 static int dhcp_tx ( struct dhcp_session *dhcp ) {
566
-	static struct sockaddr_in proxydhcp_server = {
587
+	static struct sockaddr_in dest = {
567 588
 		.sin_family = AF_INET,
568 589
 		.sin_port = htons ( PROXYDHCP_PORT ),
569 590
 	};
570
-	static struct sockaddr_in client = {
591
+	static struct sockaddr_in src = {
571 592
 		.sin_family = AF_INET,
572 593
 		.sin_port = htons ( BOOTPC_PORT ),
573 594
 	};
@@ -576,9 +597,11 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
576 597
 	};
577 598
 	struct io_buffer *iobuf;
578 599
 	struct dhcp_packet dhcppkt;
579
-	struct dhcp_packet *offer = NULL;
580 600
 	struct in_addr ciaddr = { 0 };
581
-	int check_len;
601
+	struct in_addr server = { 0 };
602
+	struct in_addr requested_ip = { 0 };
603
+	struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
604
+	unsigned int msgtype;
582 605
 	int rc;
583 606
 
584 607
 	/* Start retry timer.  Do this first so that failures to
@@ -589,59 +612,82 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
589 612
 	/* Determine packet contents based on current state */
590 613
 	switch ( dhcp->state ) {
591 614
 	case DHCP_STATE_DISCOVER:
592
-		DBGC ( dhcp, "DHCP %p transmitting DHCPDISCOVER\n", dhcp );
615
+		msgtype = DHCPDISCOVER;
593 616
 		break;
594 617
 	case DHCP_STATE_REQUEST:
595
-		DBGC ( dhcp, "DHCP %p transmitting DHCPREQUEST\n", dhcp );
596 618
 		assert ( dhcp->dhcpoffer );
597
-		offer = &dhcp->dhcpoffer->dhcppkt;
619
+		msgtype = DHCPREQUEST;
620
+		dhcppkt_fetch ( &dhcp->dhcpoffer->dhcppkt,
621
+				DHCP_SERVER_IDENTIFIER, &server,
622
+				sizeof ( server ) );
623
+		requested_ip = dhcp->dhcpoffer->dhcppkt.dhcphdr->yiaddr;
598 624
 		break;
599 625
 	case DHCP_STATE_PROXYREQUEST:
600
-		DBGC ( dhcp, "DHCP %p transmitting ProxyDHCPREQUEST\n", dhcp );
601 626
 		assert ( dhcp->dhcpoffer );
602 627
 		assert ( dhcp->proxydhcpoffer );
603 628
 		assert ( dhcp->dhcpack );
604
-		offer = &dhcp->proxydhcpoffer->dhcppkt;
629
+		msgtype = DHCPREQUEST;
605 630
 		ciaddr = dhcp->dhcpoffer->dhcppkt.dhcphdr->yiaddr;
606
-		check_len = dhcppkt_fetch ( offer, DHCP_SERVER_IDENTIFIER,
607
-					    &proxydhcp_server.sin_addr,
608
-					    sizeof(proxydhcp_server.sin_addr));
609
-		meta.dest = ( struct sockaddr * ) &proxydhcp_server;
610
-		assert ( ciaddr.s_addr != 0 );
611
-		assert ( proxydhcp_server.sin_addr.s_addr != 0 );
612
-		assert ( check_len == sizeof ( proxydhcp_server.sin_addr ) );
631
+		dhcppkt_fetch ( &dhcp->proxydhcpoffer->dhcppkt,
632
+				DHCP_SERVER_IDENTIFIER, &dest.sin_addr,
633
+				sizeof ( dest.sin_addr ) );
634
+		meta.dest = ( struct sockaddr * ) &dest;
635
+		server = dest.sin_addr;
636
+		assert ( dest.sin_addr.s_addr );
637
+		assert ( ciaddr.s_addr );
613 638
 		break;
614 639
 	case DHCP_STATE_BSREQUEST:
615
-		DBGC ( dhcp, "DHCP %p transmitting BootServerREQUEST\n",
616
-		       dhcp );
617 640
 		assert ( dhcp->dhcpoffer );
618 641
 		assert ( dhcp->proxydhcpoffer );
619 642
 		assert ( dhcp->dhcpack );
620 643
 		assert ( dhcp->proxydhcpack );
621
-		offer = &dhcp->proxydhcpoffer->dhcppkt;
644
+		msgtype = DHCPREQUEST;
622 645
 		ciaddr = dhcp->dhcpoffer->dhcppkt.dhcphdr->yiaddr;
623
-		check_len = dhcppkt_fetch ( &dhcp->proxydhcpack->dhcppkt,
624
-					    DHCP_PXE_BOOT_SERVER_MCAST,
625
-					    &proxydhcp_server.sin_addr,
626
-					    sizeof(proxydhcp_server.sin_addr));
627
-		meta.dest = ( struct sockaddr * ) &proxydhcp_server;
628
-		assert ( ciaddr.s_addr != 0 );
629
-		assert ( proxydhcp_server.sin_addr.s_addr != 0 );
630
-		assert ( check_len == sizeof ( proxydhcp_server.sin_addr ) );
646
+		dhcppkt_fetch ( &dhcp->proxydhcpack->dhcppkt,
647
+				DHCP_PXE_BOOT_SERVER_MCAST,
648
+				&dest.sin_addr, sizeof ( dest.sin_addr ) );
649
+		meta.dest = ( struct sockaddr * ) &dest;
650
+		dhcppkt_fetch ( &dhcp->proxydhcpack->dhcppkt,
651
+				DHCP_PXE_BOOT_MENU, &menu_item.type,
652
+				sizeof ( menu_item.type ) );
653
+		assert ( dest.sin_addr.s_addr );
654
+		assert ( menu_item.type );
655
+		assert ( ciaddr.s_addr );
631 656
 		break;
632 657
 	default:
633 658
 		assert ( 0 );
634
-		break;
659
+		return -EINVAL;
635 660
 	}
636 661
 
662
+	DBGC ( dhcp, "DHCP %p %s", dhcp, dhcp_msgtype_name ( msgtype ) );
663
+	if ( server.s_addr )
664
+		DBGC ( dhcp, " to %s", inet_ntoa ( server ) );
665
+	if ( meta.dest ) {
666
+		if ( dest.sin_addr.s_addr == server.s_addr ) {
667
+			DBGC ( dhcp, ":%d (unicast)",
668
+			       ntohs ( dest.sin_port ) );
669
+		} else {
670
+			DBGC ( dhcp, " via %s:%d", inet_ntoa ( dest.sin_addr ),
671
+			       ntohs ( dest.sin_port ) );
672
+		}
673
+	} else {
674
+		DBGC ( dhcp, " (broadcast)" );
675
+	}
676
+	if ( requested_ip.s_addr )
677
+		DBGC ( dhcp, " for %s", inet_ntoa ( requested_ip ) );
678
+	if ( menu_item.type )
679
+		DBGC ( dhcp, " for item %04x", ntohs ( menu_item.type ) );
680
+	DBGC ( dhcp, "\n" );
681
+
637 682
 	/* Allocate buffer for packet */
638 683
 	iobuf = xfer_alloc_iob ( &dhcp->xfer, DHCP_MIN_LEN );
639 684
 	if ( ! iobuf )
640 685
 		return -ENOMEM;
641 686
 
642 687
 	/* Create DHCP packet in temporary buffer */
643
-	if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev,
644
-					  ciaddr, offer, iobuf->data,
688
+	if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
689
+					  ciaddr, server, requested_ip,
690
+					  &menu_item, iobuf->data,
645 691
 					  iob_tailroom ( iobuf ) ) ) != 0 ) {
646 692
 		DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
647 693
 		       dhcp, strerror ( rc ) );
@@ -650,8 +696,8 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
650 696
 
651 697
 	/* Explicitly specify source address, if available. */
652 698
 	if ( ciaddr.s_addr ) {
653
-		client.sin_addr = ciaddr;
654
-		meta.src = ( struct sockaddr * ) &client;
699
+		src.sin_addr = ciaddr;
700
+		meta.src = ( struct sockaddr * ) &src;
655 701
 	}
656 702
 
657 703
 	/* Transmit the packet */
@@ -756,7 +802,7 @@ static void dhcp_store_dhcpoffer ( struct dhcp_session *dhcp,
756 802
 			DBGC ( dhcp, "DHCP %p stored DHCPOFFER %p discarded\n",
757 803
 			       dhcp, *stored_dhcpoffer );
758 804
 		}
759
-		DBGC ( dhcp, "DHCP %p received DHCPOFFER %p stored\n",
805
+		DBGC ( dhcp, "DHCP %p DHCPOFFER %p stored\n",
760 806
 		       dhcp, dhcpoffer );
761 807
 		dhcpset_put ( *stored_dhcpoffer );
762 808
 		*stored_dhcpoffer = dhcpset_get ( dhcpoffer );
@@ -781,16 +827,17 @@ static void dhcp_rx_dhcpoffer ( struct dhcp_session *dhcp,
781 827
 	if ( dhcppkt_fetch ( &dhcpoffer->dhcppkt, DHCP_SERVER_IDENTIFIER,
782 828
 			     &server_id, sizeof ( server_id ) )
783 829
 	     != sizeof ( server_id ) ) {
784
-		DBGC ( dhcp, "DHCP %p received DHCPOFFER %p missing server "
785
-		       "identifier\n", dhcp, dhcpoffer );
830
+		DBGC ( dhcp, "DHCP %p DHCPOFFER %p missing server ID\n",
831
+		       dhcp, dhcpoffer );
786 832
 		/* Could be a valid BOOTP offer; do not abort processing */
787 833
 	}
788 834
 
789 835
 	/* If there is an IP address, it's a normal DHCPOFFER */
790 836
 	if ( dhcpoffer->dhcppkt.dhcphdr->yiaddr.s_addr != 0 ) {
791
-		DBGC ( dhcp, "DHCP %p received DHCPOFFER %p from %s has IP "
792
-		       "address\n",
837
+		DBGC ( dhcp, "DHCP %p DHCPOFFER %p from %s",
793 838
 		       dhcp, dhcpoffer, inet_ntoa ( server_id ) );
839
+		DBGC ( dhcp, " has IP %s\n",
840
+		       inet_ntoa ( dhcpoffer->dhcppkt.dhcphdr->yiaddr ) );
794 841
 		dhcp_store_dhcpoffer ( dhcp, dhcpoffer, &dhcp->dhcpoffer );
795 842
 	}
796 843
 
@@ -803,7 +850,7 @@ static void dhcp_rx_dhcpoffer ( struct dhcp_session *dhcp,
803 850
 	if ( ( server_id.s_addr != 0 ) &&
804 851
 	     ( len >= ( int ) sizeof ( vci ) ) &&
805 852
 	     ( strncmp ( "PXEClient", vci, sizeof ( vci ) ) == 0 ) ) {
806
-		DBGC ( dhcp, "DHCP %p received DHCPOFFER %p from %s is a "
853
+		DBGC ( dhcp, "DHCP %p DHCPOFFER %p from %s is a "
807 854
 		       "ProxyDHCPOFFER\n",
808 855
 		       dhcp, dhcpoffer, inet_ntoa ( server_id ) );
809 856
 		dhcp_store_dhcpoffer ( dhcp, dhcpoffer,
@@ -992,7 +1039,7 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
992 1039
 			      struct xfer_metadata *meta ) {
993 1040
 	struct dhcp_session *dhcp =
994 1041
 		container_of ( xfer, struct dhcp_session, xfer );
995
-	struct sockaddr_tcpip *st_src;
1042
+	struct sockaddr_in *sin_src;
996 1043
 	unsigned int src_port;
997 1044
 	struct dhcp_settings *dhcpset;
998 1045
 	struct dhcphdr *dhcphdr;
@@ -1012,8 +1059,8 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
1012 1059
 		rc = -EINVAL;
1013 1060
 		goto err_no_src;
1014 1061
 	}
1015
-	st_src = ( struct sockaddr_tcpip * ) meta->src;
1016
-	src_port = st_src->st_port;
1062
+	sin_src = ( struct sockaddr_in * ) meta->src;
1063
+	src_port = sin_src->sin_port;
1017 1064
 
1018 1065
 	/* Convert packet into a DHCP settings block */
1019 1066
 	dhcpset = dhcpset_create ( iobuf->data, iob_len ( iobuf ) );
@@ -1027,12 +1074,13 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
1027 1074
 	/* Identify message type */
1028 1075
 	dhcppkt_fetch ( &dhcpset->dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
1029 1076
 			sizeof ( msgtype ) );
1030
-	DBGC ( dhcp, "DHCP %p received %s %p from port %d\n", dhcp,
1031
-	       dhcp_msgtype_name ( msgtype ), dhcpset, ntohs ( src_port ) );
1077
+	DBGC ( dhcp, "DHCP %p %s %p from %s:%d\n", dhcp,
1078
+	       dhcp_msgtype_name ( msgtype ), dhcpset,
1079
+	       inet_ntoa ( sin_src->sin_addr ), ntohs ( src_port ) );
1032 1080
 
1033 1081
 	/* Check for matching transaction ID */
1034 1082
 	if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
1035
-		DBGC ( dhcp, "DHCP %p received %s %p has bad transaction ID\n",
1083
+		DBGC ( dhcp, "DHCP %p %s %p has bad transaction ID\n",
1036 1084
 		       dhcp, dhcp_msgtype_name ( msgtype ), dhcpset );
1037 1085
 		rc = -EINVAL;
1038 1086
 		goto err_xid;

Loading…
Cancel
Save