Browse Source

[dhcp] Add preliminary support for PXE Boot Servers

Some PXE configurations require us to perform a third DHCP transaction
(in addition to the real DHCP transaction and the ProxyDHCP
transaction) in order to retrieve information from a "Boot Server".

This is an experimental implementation, since the actual behaviour is
not well specified in the PXE spec.
tags/v0.9.7
Michael Brown 16 years ago
parent
commit
6941793416
3 changed files with 109 additions and 1 deletions
  1. 6
    0
      src/include/gpxe/dhcp.h
  2. 11
    0
      src/net/fakedhcp.c
  3. 92
    1
      src/net/udp/dhcp.c

+ 6
- 0
src/include/gpxe/dhcp.h View File

81
 /** Vendor encapsulated options */
81
 /** Vendor encapsulated options */
82
 #define DHCP_VENDOR_ENCAP 43
82
 #define DHCP_VENDOR_ENCAP 43
83
 
83
 
84
+/** PXE boot server multicast address */
85
+#define DHCP_PXE_BOOT_SERVER_MCAST DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 7 )
86
+
84
 /** Requested IP address */
87
 /** Requested IP address */
85
 #define DHCP_REQUESTED_ADDRESS 50
88
 #define DHCP_REQUESTED_ADDRESS 50
86
 
89
 
480
 /** Settings block name used for ProxyDHCP responses */
483
 /** Settings block name used for ProxyDHCP responses */
481
 #define PROXYDHCP_SETTINGS_NAME "proxydhcp"
484
 #define PROXYDHCP_SETTINGS_NAME "proxydhcp"
482
 
485
 
486
+/** Setting block name used for BootServerDHCP responses */
487
+#define BSDHCP_SETTINGS_NAME "bs"
488
+
483
 extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
489
 extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
484
 				struct net_device *netdev, uint8_t msgtype,
490
 				struct net_device *netdev, uint8_t msgtype,
485
 				struct dhcp_options *options, 
491
 				struct dhcp_options *options, 

+ 11
- 0
src/net/fakedhcp.c View File

176
 			      void *data, size_t max_len ) {
176
 			      void *data, size_t max_len ) {
177
 	struct dhcp_packet dhcppkt;
177
 	struct dhcp_packet dhcppkt;
178
 	struct settings *settings;
178
 	struct settings *settings;
179
+	struct settings *bs_settings;
179
 	int rc;
180
 	int rc;
180
 
181
 
181
 	/* Identify ProxyDHCP settings */
182
 	/* Identify ProxyDHCP settings */
200
 		return rc;
201
 		return rc;
201
 	}
202
 	}
202
 
203
 
204
+	/* Merge in BootServerDHCP options, if present */
205
+	bs_settings = find_settings ( BSDHCP_SETTINGS_NAME );
206
+	if ( bs_settings ) {
207
+		if ( ( rc = copy_settings ( &dhcppkt, bs_settings ) ) != 0 ) {
208
+			DBG ( "Could not set BootServerDHCPACK settings: "
209
+			      "%s\n", strerror ( rc ) );
210
+			return rc;
211
+		}
212
+	}
213
+
203
 	return 0;
214
 	return 0;
204
 }
215
 }

+ 92
- 1
src/net/udp/dhcp.c View File

287
 	DHCP_STATE_REQUEST,
287
 	DHCP_STATE_REQUEST,
288
 	/** Sending ProxyDHCPREQUESTs, waiting for ProxyDHCPACK */
288
 	/** Sending ProxyDHCPREQUESTs, waiting for ProxyDHCPACK */
289
 	DHCP_STATE_PROXYREQUEST,
289
 	DHCP_STATE_PROXYREQUEST,
290
+	/** Sending BootServerDHCPREQUESTs, waiting for BootServerDHCPACK */
291
+	DHCP_STATE_BSREQUEST,
290
 };
292
 };
291
 
293
 
292
 /**
294
 /**
300
 	case DHCP_STATE_DISCOVER:	return "DHCPDISCOVER";
302
 	case DHCP_STATE_DISCOVER:	return "DHCPDISCOVER";
301
 	case DHCP_STATE_REQUEST:	return "DHCPREQUEST";
303
 	case DHCP_STATE_REQUEST:	return "DHCPREQUEST";
302
 	case DHCP_STATE_PROXYREQUEST:	return "ProxyDHCPREQUEST";
304
 	case DHCP_STATE_PROXYREQUEST:	return "ProxyDHCPREQUEST";
305
+	case DHCP_STATE_BSREQUEST:	return "BootServerREQUEST";
303
 	default:			return "<invalid>";
306
 	default:			return "<invalid>";
304
 	}
307
 	}
305
 }
308
 }
326
 	struct dhcp_settings *dhcpoffer;
329
 	struct dhcp_settings *dhcpoffer;
327
 	/** ProxyDHCPOFFER obtained during DHCPDISCOVER */
330
 	/** ProxyDHCPOFFER obtained during DHCPDISCOVER */
328
 	struct dhcp_settings *proxydhcpoffer;
331
 	struct dhcp_settings *proxydhcpoffer;
332
+	/** DHCPACK obtained during DHCPREQUEST */
333
+	struct dhcp_settings *dhcpack;
334
+	/** ProxyDHCPACK obtained during ProxyDHCPREQUEST */
335
+	struct dhcp_settings *proxydhcpack;
336
+	/** BootServerDHCPACK obtained during BootServerDHCPREQUEST */
337
+	struct dhcp_settings *bsdhcpack;
329
 	/** Retransmission timer */
338
 	/** Retransmission timer */
330
 	struct retry_timer timer;
339
 	struct retry_timer timer;
331
 	/** Start time of the current state (in ticks) */
340
 	/** Start time of the current state (in ticks) */
344
 	netdev_put ( dhcp->netdev );
353
 	netdev_put ( dhcp->netdev );
345
 	dhcpset_put ( dhcp->dhcpoffer );
354
 	dhcpset_put ( dhcp->dhcpoffer );
346
 	dhcpset_put ( dhcp->proxydhcpoffer );
355
 	dhcpset_put ( dhcp->proxydhcpoffer );
356
+	dhcpset_put ( dhcp->dhcpack );
357
+	dhcpset_put ( dhcp->proxydhcpack );
358
+	dhcpset_put ( dhcp->bsdhcpack );
347
 	free ( dhcp );
359
 	free ( dhcp );
348
 }
360
 }
349
 
361
 
555
 		.sin_family = AF_INET,
567
 		.sin_family = AF_INET,
556
 		.sin_port = htons ( PROXYDHCP_PORT ),
568
 		.sin_port = htons ( PROXYDHCP_PORT ),
557
 	};
569
 	};
570
+	static struct sockaddr_in client = {
571
+		.sin_family = AF_INET,
572
+		.sin_port = htons ( BOOTPC_PORT ),
573
+	};
558
 	struct xfer_metadata meta = {
574
 	struct xfer_metadata meta = {
559
 		.netdev = dhcp->netdev,
575
 		.netdev = dhcp->netdev,
560
 	};
576
 	};
584
 		DBGC ( dhcp, "DHCP %p transmitting ProxyDHCPREQUEST\n", dhcp );
600
 		DBGC ( dhcp, "DHCP %p transmitting ProxyDHCPREQUEST\n", dhcp );
585
 		assert ( dhcp->dhcpoffer );
601
 		assert ( dhcp->dhcpoffer );
586
 		assert ( dhcp->proxydhcpoffer );
602
 		assert ( dhcp->proxydhcpoffer );
603
+		assert ( dhcp->dhcpack );
587
 		offer = &dhcp->proxydhcpoffer->dhcppkt;
604
 		offer = &dhcp->proxydhcpoffer->dhcppkt;
588
 		ciaddr = dhcp->dhcpoffer->dhcppkt.dhcphdr->yiaddr;
605
 		ciaddr = dhcp->dhcpoffer->dhcppkt.dhcphdr->yiaddr;
589
 		check_len = dhcppkt_fetch ( offer, DHCP_SERVER_IDENTIFIER,
606
 		check_len = dhcppkt_fetch ( offer, DHCP_SERVER_IDENTIFIER,
594
 		assert ( proxydhcp_server.sin_addr.s_addr != 0 );
611
 		assert ( proxydhcp_server.sin_addr.s_addr != 0 );
595
 		assert ( check_len == sizeof ( proxydhcp_server.sin_addr ) );
612
 		assert ( check_len == sizeof ( proxydhcp_server.sin_addr ) );
596
 		break;
613
 		break;
614
+	case DHCP_STATE_BSREQUEST:
615
+		DBGC ( dhcp, "DHCP %p transmitting BootServerREQUEST\n",
616
+		       dhcp );
617
+		assert ( dhcp->dhcpoffer );
618
+		assert ( dhcp->proxydhcpoffer );
619
+		assert ( dhcp->dhcpack );
620
+		assert ( dhcp->proxydhcpack );
621
+		offer = &dhcp->proxydhcpoffer->dhcppkt;
622
+		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 ) );
631
+		break;
597
 	default:
632
 	default:
598
 		assert ( 0 );
633
 		assert ( 0 );
599
 		break;
634
 		break;
613
 		goto done;
648
 		goto done;
614
 	}
649
 	}
615
 
650
 
651
+	/* Explicitly specify source address, if available. */
652
+	if ( ciaddr.s_addr ) {
653
+		client.sin_addr = ciaddr;
654
+		meta.src = ( struct sockaddr * ) &client;
655
+	}
656
+
616
 	/* Transmit the packet */
657
 	/* Transmit the packet */
617
 	iob_put ( iobuf, dhcppkt.len );
658
 	iob_put ( iobuf, dhcppkt.len );
618
 	rc = xfer_deliver_iob_meta ( &dhcp->xfer, iobuf, &meta );
659
 	rc = xfer_deliver_iob_meta ( &dhcp->xfer, iobuf, &meta );
650
  * @v dhcp		DHCP session
691
  * @v dhcp		DHCP session
651
  */
692
  */
652
 static void dhcp_next_state ( struct dhcp_session *dhcp ) {
693
 static void dhcp_next_state ( struct dhcp_session *dhcp ) {
694
+	struct in_addr bs_mcast = { 0 };
653
 
695
 
654
 	switch ( dhcp->state ) {
696
 	switch ( dhcp->state ) {
655
 	case DHCP_STATE_DISCOVER:
697
 	case DHCP_STATE_DISCOVER:
662
 		}
704
 		}
663
 		/* Fall through */
705
 		/* Fall through */
664
 	case DHCP_STATE_PROXYREQUEST:
706
 	case DHCP_STATE_PROXYREQUEST:
707
+		if ( dhcp->proxydhcpack ) {
708
+			dhcppkt_fetch ( &dhcp->proxydhcpack->dhcppkt,
709
+					DHCP_PXE_BOOT_SERVER_MCAST,
710
+					&bs_mcast, sizeof ( bs_mcast ) );
711
+			if ( bs_mcast.s_addr ) {
712
+				dhcp_set_state ( dhcp, DHCP_STATE_BSREQUEST );
713
+				break;
714
+			}
715
+		}
716
+		/* Fall through */
717
+	case DHCP_STATE_BSREQUEST:
665
 		dhcp_finished ( dhcp, 0 );
718
 		dhcp_finished ( dhcp, 0 );
666
 		break;
719
 		break;
667
 	default:
720
 	default:
845
 		return;
898
 		return;
846
 	}
899
 	}
847
 
900
 
901
+	/* Record DHCPACK */
902
+	assert ( dhcp->dhcpack == NULL );
903
+	dhcp->dhcpack = dhcpset_get ( dhcpack );
904
+
848
 	/* Register settings */
905
 	/* Register settings */
849
 	parent = netdev_settings ( dhcp->netdev );
906
 	parent = netdev_settings ( dhcp->netdev );
850
-	if ( ( rc = dhcp_store_dhcpack ( dhcp, dhcpack, parent ) ) !=0 )
907
+	if ( ( rc = dhcp_store_dhcpack ( dhcp, dhcpack, parent ) ) != 0 )
851
 		return;
908
 		return;
852
 
909
 
853
 	/* Transition to next state */
910
 	/* Transition to next state */
885
 	/* Rename settings */
942
 	/* Rename settings */
886
 	proxydhcpack->settings.name = PROXYDHCP_SETTINGS_NAME;
943
 	proxydhcpack->settings.name = PROXYDHCP_SETTINGS_NAME;
887
 
944
 
945
+	/* Record ProxyDHCPACK */
946
+	assert ( dhcp->proxydhcpack == NULL );
947
+	dhcp->proxydhcpack = dhcpset_get ( proxydhcpack );
948
+
888
 	/* Register settings */
949
 	/* Register settings */
889
 	if ( ( rc = dhcp_store_dhcpack ( dhcp, proxydhcpack, NULL ) ) != 0 )
950
 	if ( ( rc = dhcp_store_dhcpack ( dhcp, proxydhcpack, NULL ) ) != 0 )
890
 		return;
951
 		return;
893
 	dhcp_next_state ( dhcp );
954
 	dhcp_next_state ( dhcp );
894
 }
955
 }
895
 
956
 
957
+/**
958
+ * Handle received BootServerDHCPACK
959
+ *
960
+ * @v dhcp		DHCP session
961
+ * @v bsdhcpack	Received BootServerDHCPACK
962
+ */
963
+static void dhcp_rx_bsdhcpack ( struct dhcp_session *dhcp,
964
+				struct dhcp_settings *bsdhcpack ) {
965
+	int rc;
966
+
967
+	/* Rename settings */
968
+	bsdhcpack->settings.name = BSDHCP_SETTINGS_NAME;
969
+
970
+	/* Record ProxyDHCPACK */
971
+	assert ( dhcp->bsdhcpack == NULL );
972
+	dhcp->bsdhcpack = dhcpset_get ( bsdhcpack );
973
+
974
+	/* Register settings */
975
+	if ( ( rc = dhcp_store_dhcpack ( dhcp, bsdhcpack, NULL ) ) != 0 )
976
+		return;
977
+
978
+	/* Transition to next state */
979
+	dhcp_next_state ( dhcp );
980
+}
981
+
896
 /**
982
 /**
897
  * Receive new data
983
  * Receive new data
898
  *
984
  *
969
 		     ( src_port == htons ( PROXYDHCP_PORT ) ) )
1055
 		     ( src_port == htons ( PROXYDHCP_PORT ) ) )
970
 			dhcp_rx_proxydhcpack ( dhcp, dhcpset );
1056
 			dhcp_rx_proxydhcpack ( dhcp, dhcpset );
971
 		break;
1057
 		break;
1058
+	case DHCP_STATE_BSREQUEST:
1059
+		if ( ( msgtype == DHCPACK ) &&
1060
+		     ( src_port == htons ( PROXYDHCP_PORT ) ) )
1061
+			dhcp_rx_bsdhcpack ( dhcp, dhcpset );
1062
+		break;
972
 	default:
1063
 	default:
973
 		assert ( 0 );
1064
 		assert ( 0 );
974
 		break;
1065
 		break;

Loading…
Cancel
Save