Browse Source

[pxe] Obey lists of PXE Boot Servers and associated Discovery Control bits

Various combinations of options 43.6, 43.7 and 43.8 dictate which
servers we send Boot Server Discovery requests to, and which servers
we should accept responses from.  Obey these options, and remove the
explicit specification of a single Boot Server from start_pxebs() and
dependent functions.
tags/v0.9.7
Michael Brown 16 years ago
parent
commit
881f1f59ef
6 changed files with 195 additions and 62 deletions
  1. 4
    13
      src/hci/commands/dhcp_cmd.c
  2. 17
    1
      src/include/gpxe/dhcp.h
  3. 1
    2
      src/include/usr/dhcpmgmt.h
  4. 169
    29
      src/net/udp/dhcp.c
  5. 3
    6
      src/usr/dhcpmgmt.c
  6. 1
    11
      src/usr/pxemenu.c

+ 4
- 13
src/hci/commands/dhcp_cmd.c View File

109
  */
109
  */
110
 static void pxebs_syntax ( char **argv ) {
110
 static void pxebs_syntax ( char **argv ) {
111
 	printf ( "Usage:\n"
111
 	printf ( "Usage:\n"
112
-		 "  %s <interface> <discovery_ip> <server_type>\n"
112
+		 "  %s <interface> <server_type>\n"
113
 		 "\n"
113
 		 "\n"
114
 		 "Perform PXE Boot Server discovery\n",
114
 		 "Perform PXE Boot Server discovery\n",
115
 		 argv[0] );
115
 		 argv[0] );
128
 		{ NULL, 0, NULL, 0 },
128
 		{ NULL, 0, NULL, 0 },
129
 	};
129
 	};
130
 	const char *netdev_txt;
130
 	const char *netdev_txt;
131
-	const char *pxe_server_txt;
132
 	const char *pxe_type_txt;
131
 	const char *pxe_type_txt;
133
 	struct net_device *netdev;
132
 	struct net_device *netdev;
134
-	struct in_addr pxe_server;
135
 	unsigned int pxe_type;
133
 	unsigned int pxe_type;
136
 	char *end;
134
 	char *end;
137
 	int c;
135
 	int c;
148
 			return 1;
146
 			return 1;
149
 		}
147
 		}
150
 	}
148
 	}
151
-
152
-	/* Need exactly one interface name remaining after the options */
153
-	if ( optind != ( argc - 3 ) ) {
149
+	if ( optind != ( argc - 2 ) ) {
154
 		pxebs_syntax ( argv );
150
 		pxebs_syntax ( argv );
155
 		return 1;
151
 		return 1;
156
 	}
152
 	}
157
 	netdev_txt = argv[optind];
153
 	netdev_txt = argv[optind];
158
-	pxe_server_txt = argv[ optind + 1 ];
159
-	pxe_type_txt = argv[ optind + 2 ];
154
+	pxe_type_txt = argv[ optind + 1 ];
160
 
155
 
161
 	/* Parse arguments */
156
 	/* Parse arguments */
162
 	netdev = find_netdev ( netdev_txt );
157
 	netdev = find_netdev ( netdev_txt );
164
 		printf ( "No such interface: %s\n", netdev_txt );
159
 		printf ( "No such interface: %s\n", netdev_txt );
165
 		return 1;
160
 		return 1;
166
 	}
161
 	}
167
-	if ( inet_aton ( pxe_server_txt, &pxe_server ) == 0 ) {
168
-		printf ( "Bad discovery IP address: %s\n", pxe_server_txt );
169
-		return 1;
170
-	}
171
 	pxe_type = strtoul ( pxe_type_txt, &end, 0 );
162
 	pxe_type = strtoul ( pxe_type_txt, &end, 0 );
172
 	if ( *end ) {
163
 	if ( *end ) {
173
 		printf ( "Bad server type: %s\n", pxe_type_txt );
164
 		printf ( "Bad server type: %s\n", pxe_type_txt );
175
 	}
166
 	}
176
 
167
 
177
 	/* Perform Boot Server Discovery */
168
 	/* Perform Boot Server Discovery */
178
-	if ( ( rc = pxebs ( netdev, pxe_server, pxe_type ) ) != 0 ) {
169
+	if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 ) {
179
 		printf ( "Could not discover boot server on %s: %s\n",
170
 		printf ( "Could not discover boot server on %s: %s\n",
180
 			 netdev->name, strerror ( rc ) );
171
 			 netdev->name, strerror ( rc ) );
181
 		return 1;
172
 		return 1;

+ 17
- 1
src/include/gpxe/dhcp.h View File

100
 /** PXE boot server multicast address */
100
 /** PXE boot server multicast address */
101
 #define DHCP_PXE_BOOT_SERVER_MCAST DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 7 )
101
 #define DHCP_PXE_BOOT_SERVER_MCAST DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 7 )
102
 
102
 
103
+/** PXE boot servers */
104
+#define DHCP_PXE_BOOT_SERVERS DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 8 )
105
+
106
+/** PXE boot server */
107
+struct dhcp_pxe_boot_server {
108
+	/** "Type" */
109
+	uint16_t type;
110
+	/** Number of IPv4 addresses */
111
+	uint8_t num_ip;
112
+	/** IPv4 addresses */
113
+	struct in_addr ip[0];
114
+} __attribute__ (( packed ));
115
+
103
 /** PXE boot menu */
116
 /** PXE boot menu */
104
 #define DHCP_PXE_BOOT_MENU DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 9 )
117
 #define DHCP_PXE_BOOT_MENU DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 9 )
105
 
118
 
574
 /** Maximum time that we will wait for ProxyDHCP responses */
587
 /** Maximum time that we will wait for ProxyDHCP responses */
575
 #define PROXYDHCP_MAX_TIMEOUT ( 2 * TICKS_PER_SEC )
588
 #define PROXYDHCP_MAX_TIMEOUT ( 2 * TICKS_PER_SEC )
576
 
589
 
590
+/** Maximum time that we will wait for Boot Server responses */
591
+#define PXEBS_MAX_TIMEOUT ( 3 * TICKS_PER_SEC )
592
+
577
 /** Settings block name used for DHCP responses */
593
 /** Settings block name used for DHCP responses */
578
 #define DHCP_SETTINGS_NAME "dhcp"
594
 #define DHCP_SETTINGS_NAME "dhcp"
579
 
595
 
593
 				 void *data, size_t max_len );
609
 				 void *data, size_t max_len );
594
 extern int start_dhcp ( struct job_interface *job, struct net_device *netdev );
610
 extern int start_dhcp ( struct job_interface *job, struct net_device *netdev );
595
 extern int start_pxebs ( struct job_interface *job, struct net_device *netdev,
611
 extern int start_pxebs ( struct job_interface *job, struct net_device *netdev,
596
-			 struct in_addr pxe_server, unsigned int pxe_type );
612
+			 unsigned int pxe_type );
597
 
613
 
598
 #endif /* _GPXE_DHCP_H */
614
 #endif /* _GPXE_DHCP_H */

+ 1
- 2
src/include/usr/dhcpmgmt.h View File

10
 struct net_device;
10
 struct net_device;
11
 
11
 
12
 extern int dhcp ( struct net_device *netdev );
12
 extern int dhcp ( struct net_device *netdev );
13
-extern int pxebs ( struct net_device *netdev, struct in_addr pxe_server,
14
-		   unsigned int pxe_type );
13
+extern int pxebs ( struct net_device *netdev, unsigned int pxe_type );
15
 
14
 
16
 #endif /* _USR_DHCPMGMT_H */
15
 #endif /* _USR_DHCPMGMT_H */

+ 169
- 29
src/net/udp/dhcp.c View File

175
 	 * @v dhcppkt		DHCP packet
175
 	 * @v dhcppkt		DHCP packet
176
 	 * @v peer		DHCP server address
176
 	 * @v peer		DHCP server address
177
 	 * @v msgtype		DHCP message type
177
 	 * @v msgtype		DHCP message type
178
+	 * @v server_id		DHCP server ID
178
 	 */
179
 	 */
179
 	void ( * rx ) ( struct dhcp_session *dhcp,
180
 	void ( * rx ) ( struct dhcp_session *dhcp,
180
 			struct dhcp_packet *dhcppkt,
181
 			struct dhcp_packet *dhcppkt,
181
 			struct sockaddr_in *peer,
182
 			struct sockaddr_in *peer,
182
-			uint8_t msgtype );
183
+			uint8_t msgtype, struct in_addr server_id );
183
 	/** Handle timer expiry
184
 	/** Handle timer expiry
184
 	 *
185
 	 *
185
 	 * @v dhcp		DHCP session
186
 	 * @v dhcp		DHCP session
226
 	/** ProxyDHCP server priority */
227
 	/** ProxyDHCP server priority */
227
 	int proxy_priority;
228
 	int proxy_priority;
228
 
229
 
229
-	/** PXE Boot Server */
230
-	struct in_addr pxe_server;
231
 	/** PXE Boot Server type */
230
 	/** PXE Boot Server type */
232
 	uint16_t pxe_type;
231
 	uint16_t pxe_type;
232
+	/** List of PXE Boot Servers to attempt */
233
+	struct in_addr *pxe_attempt;
234
+	/** List of PXE Boot Servers to accept */
235
+	struct in_addr *pxe_accept;
233
 
236
 
234
 	/** Retransmission timer */
237
 	/** Retransmission timer */
235
 	struct retry_timer timer;
238
 	struct retry_timer timer;
322
  * @v dhcppkt		DHCP packet
325
  * @v dhcppkt		DHCP packet
323
  * @v peer		DHCP server address
326
  * @v peer		DHCP server address
324
  * @v msgtype		DHCP message type
327
  * @v msgtype		DHCP message type
328
+ * @v server_id		DHCP server ID
325
  */
329
  */
326
 static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
330
 static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
327
 				struct dhcp_packet *dhcppkt,
331
 				struct dhcp_packet *dhcppkt,
328
-				struct sockaddr_in *peer, uint8_t msgtype ) {
329
-	struct in_addr server_id = { 0 };
332
+				struct sockaddr_in *peer, uint8_t msgtype,
333
+				struct in_addr server_id ) {
330
 	struct in_addr ip;
334
 	struct in_addr ip;
331
 	char vci[9]; /* "PXEClient" */
335
 	char vci[9]; /* "PXEClient" */
332
 	int vci_len;
336
 	int vci_len;
338
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
342
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
339
 	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
343
 	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
340
 	       ntohs ( peer->sin_port ) );
344
 	       ntohs ( peer->sin_port ) );
341
-
342
-	/* Identify server ID */
343
-	dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
344
-			&server_id, sizeof ( server_id ) );
345
 	if ( server_id.s_addr != peer->sin_addr.s_addr )
345
 	if ( server_id.s_addr != peer->sin_addr.s_addr )
346
 		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
346
 		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
347
 
347
 
480
  * @v dhcppkt		DHCP packet
480
  * @v dhcppkt		DHCP packet
481
  * @v peer		DHCP server address
481
  * @v peer		DHCP server address
482
  * @v msgtype		DHCP message type
482
  * @v msgtype		DHCP message type
483
+ * @v server_id		DHCP server ID
483
  */
484
  */
484
 static void dhcp_request_rx ( struct dhcp_session *dhcp,
485
 static void dhcp_request_rx ( struct dhcp_session *dhcp,
485
 			      struct dhcp_packet *dhcppkt,
486
 			      struct dhcp_packet *dhcppkt,
486
-			      struct sockaddr_in *peer, uint8_t msgtype ) {
487
-	struct in_addr server_id = { 0 };
487
+			      struct sockaddr_in *peer, uint8_t msgtype,
488
+			      struct in_addr server_id ) {
488
 	struct in_addr ip;
489
 	struct in_addr ip;
489
 	struct settings *parent;
490
 	struct settings *parent;
490
 	int rc;
491
 	int rc;
492
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
493
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
493
 	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
494
 	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
494
 	       ntohs ( peer->sin_port ) );
495
 	       ntohs ( peer->sin_port ) );
495
-
496
-	/* Identify server ID */
497
-	dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
498
-			&server_id, sizeof ( server_id ) );
499
 	if ( server_id.s_addr != peer->sin_addr.s_addr )
496
 	if ( server_id.s_addr != peer->sin_addr.s_addr )
500
 		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
497
 		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
501
 
498
 
591
  * @v dhcppkt		DHCP packet
588
  * @v dhcppkt		DHCP packet
592
  * @v peer		DHCP server address
589
  * @v peer		DHCP server address
593
  * @v msgtype		DHCP message type
590
  * @v msgtype		DHCP message type
591
+ * @v server_id		DHCP server ID
594
  */
592
  */
595
 static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
593
 static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
596
 			    struct dhcp_packet *dhcppkt,
594
 			    struct dhcp_packet *dhcppkt,
597
-			    struct sockaddr_in *peer, uint8_t msgtype ) {
598
-	struct in_addr server_id = { 0 };
595
+			    struct sockaddr_in *peer, uint8_t msgtype,
596
+			    struct in_addr server_id ) {
599
 	int rc;
597
 	int rc;
600
 
598
 
601
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
599
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
602
 	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
600
 	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
603
 	       ntohs ( peer->sin_port ) );
601
 	       ntohs ( peer->sin_port ) );
604
-
605
-	/* Identify server ID */
606
-	dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
607
-			&server_id, sizeof ( server_id ) );
608
 	if ( server_id.s_addr != peer->sin_addr.s_addr )
602
 	if ( server_id.s_addr != peer->sin_addr.s_addr )
609
 		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
603
 		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
610
 	DBGC ( dhcp, "\n" );
604
 	DBGC ( dhcp, "\n" );
673
 	int rc;
667
 	int rc;
674
 
668
 
675
 	DBGC ( dhcp, "DHCP %p PXEBS REQUEST to %s:%d for type %d\n",
669
 	DBGC ( dhcp, "DHCP %p PXEBS REQUEST to %s:%d for type %d\n",
676
-	       dhcp, inet_ntoa ( dhcp->pxe_server ), PXE_PORT,
670
+	       dhcp, inet_ntoa ( *(dhcp->pxe_attempt) ), PXE_PORT,
677
 	       ntohs ( dhcp->pxe_type ) );
671
 	       ntohs ( dhcp->pxe_type ) );
678
 
672
 
679
 	/* Set boot menu item */
673
 	/* Set boot menu item */
683
 		return rc;
677
 		return rc;
684
 
678
 
685
 	/* Set server address */
679
 	/* Set server address */
686
-	peer->sin_addr = dhcp->pxe_server;
680
+	peer->sin_addr = *(dhcp->pxe_attempt);
687
 	peer->sin_port = htons ( PXE_PORT );
681
 	peer->sin_port = htons ( PXE_PORT );
688
 
682
 
689
 	return 0;
683
 	return 0;
690
 }
684
 }
691
 
685
 
686
+/**
687
+ * Check to see if PXE Boot Server address is acceptable
688
+ *
689
+ * @v dhcp		DHCP session
690
+ * @v bs		Boot Server address
691
+ * @ret accept		Boot Server is acceptable
692
+ */
693
+static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
694
+			       struct in_addr bs ) {
695
+	struct in_addr *accept;
696
+
697
+	/* Accept if we have no acceptance filter */
698
+	if ( ! dhcp->pxe_accept )
699
+		return 1;
700
+
701
+	/* Scan through acceptance list */
702
+	for ( accept = dhcp->pxe_accept ; accept->s_addr ; accept++ ) {
703
+		if ( accept->s_addr == bs.s_addr )
704
+			return 1;
705
+	}
706
+
707
+	DBGC ( dhcp, "DHCP %p rejecting server %s\n",
708
+	       dhcp, inet_ntoa ( bs ) );
709
+	return 0;
710
+}
711
+
692
 /**
712
 /**
693
  * Handle received packet during PXE Boot Server Discovery
713
  * Handle received packet during PXE Boot Server Discovery
694
  *
714
  *
696
  * @v dhcppkt		DHCP packet
716
  * @v dhcppkt		DHCP packet
697
  * @v peer		DHCP server address
717
  * @v peer		DHCP server address
698
  * @v msgtype		DHCP message type
718
  * @v msgtype		DHCP message type
719
+ * @v server_id		DHCP server ID
699
  */
720
  */
700
 static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
721
 static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
701
 			    struct dhcp_packet *dhcppkt,
722
 			    struct dhcp_packet *dhcppkt,
702
-			    struct sockaddr_in *peer, uint8_t msgtype ) {
723
+			    struct sockaddr_in *peer, uint8_t msgtype,
724
+			    struct in_addr server_id ) {
703
 	struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
725
 	struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
704
 	int rc;
726
 	int rc;
705
 
727
 
706
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
728
 	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
707
 	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
729
 	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
708
 	       ntohs ( peer->sin_port ) );
730
 	       ntohs ( peer->sin_port ) );
731
+	if ( server_id.s_addr != peer->sin_addr.s_addr )
732
+		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
709
 
733
 
710
 	/* Identify boot menu item */
734
 	/* Identify boot menu item */
711
 	dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
735
 	dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
721
 		return;
745
 		return;
722
 	if ( menu_item.type != dhcp->pxe_type )
746
 	if ( menu_item.type != dhcp->pxe_type )
723
 		return;
747
 		return;
748
+	if ( ! dhcp_pxebs_accept ( dhcp, ( server_id.s_addr ?
749
+					   server_id : peer->sin_addr ) ) )
750
+		return;
724
 
751
 
725
 	/* Register settings */
752
 	/* Register settings */
726
 	dhcppkt->settings.name = PXEBS_SETTINGS_NAME;
753
 	dhcppkt->settings.name = PXEBS_SETTINGS_NAME;
741
  * @v dhcp		DHCP session
768
  * @v dhcp		DHCP session
742
  */
769
  */
743
 static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
770
 static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
771
+	unsigned long elapsed = ( currticks() - dhcp->start );
772
+
773
+	/* Give up waiting before we reach the failure point, and fail
774
+	 * over to the next server in the attempt list
775
+	 */
776
+	if ( elapsed > PXEBS_MAX_TIMEOUT ) {
777
+		dhcp->pxe_attempt++;
778
+		if ( dhcp->pxe_attempt->s_addr ) {
779
+			dhcp_set_state ( dhcp, &dhcp_state_pxebs );
780
+			return;
781
+		} else {
782
+			dhcp_finished ( dhcp, -ETIMEDOUT );
783
+			return;
784
+		}
785
+	}
744
 
786
 
745
 	/* Retransmit current packet */
787
 	/* Retransmit current packet */
746
 	dhcp_tx ( dhcp );
788
 	dhcp_tx ( dhcp );
1006
 	struct dhcp_packet *dhcppkt;
1048
 	struct dhcp_packet *dhcppkt;
1007
 	struct dhcphdr *dhcphdr;
1049
 	struct dhcphdr *dhcphdr;
1008
 	uint8_t msgtype = 0;
1050
 	uint8_t msgtype = 0;
1051
+	struct in_addr server_id = { 0 };
1009
 	int rc = 0;
1052
 	int rc = 0;
1010
 
1053
 
1011
 	/* Sanity checks */
1054
 	/* Sanity checks */
1042
 	dhcppkt_fetch ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
1085
 	dhcppkt_fetch ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
1043
 			sizeof ( msgtype ) );
1086
 			sizeof ( msgtype ) );
1044
 
1087
 
1088
+	/* Identify server ID */
1089
+	dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
1090
+			&server_id, sizeof ( server_id ) );
1091
+
1045
 	/* Check for matching transaction ID */
1092
 	/* Check for matching transaction ID */
1046
 	if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
1093
 	if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
1047
 		DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
1094
 		DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
1053
 	};
1100
 	};
1054
 
1101
 
1055
 	/* Handle packet based on current state */
1102
 	/* Handle packet based on current state */
1056
-	dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype );
1103
+	dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id );
1057
 
1104
 
1058
  err_xid:
1105
  err_xid:
1059
 	dhcppkt_put ( dhcppkt );
1106
 	dhcppkt_put ( dhcppkt );
1183
 	return rc;
1230
 	return rc;
1184
 }
1231
 }
1185
 
1232
 
1233
+/**
1234
+ * Retrieve list of PXE boot servers for a given server type
1235
+ *
1236
+ * @v dhcp		DHCP session
1237
+ * @v raw		DHCP PXE boot server list
1238
+ * @v raw_len		Length of DHCP PXE boot server list
1239
+ * @v ip		IP address list to fill in
1240
+ *
1241
+ * The caller must ensure that the IP address list has sufficient
1242
+ * space.
1243
+ */
1244
+static void pxebs_list ( struct dhcp_session *dhcp, void *raw,
1245
+			 size_t raw_len, struct in_addr *ip ) {
1246
+	struct dhcp_pxe_boot_server *server = raw;
1247
+	size_t server_len;
1248
+	unsigned int i;
1249
+
1250
+	while ( raw_len ) {
1251
+		if ( raw_len < sizeof ( *server ) ) {
1252
+			DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
1253
+			       dhcp );
1254
+			break;
1255
+		}
1256
+		server_len = offsetof ( typeof ( *server ),
1257
+					ip[ server->num_ip ] );
1258
+		if ( raw_len < server_len ) {
1259
+			DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
1260
+			       dhcp );
1261
+			break;
1262
+		}
1263
+		if ( server->type == dhcp->pxe_type ) {
1264
+			for ( i = 0 ; i < server->num_ip ; i++ )
1265
+				*(ip++) = server->ip[i];
1266
+		}
1267
+		server = ( ( ( void * ) server ) + server_len );
1268
+		raw_len -= server_len;
1269
+	}
1270
+}
1271
+
1186
 /**
1272
 /**
1187
  * Start PXE Boot Server Discovery on a network device
1273
  * Start PXE Boot Server Discovery on a network device
1188
  *
1274
  *
1189
  * @v job		Job control interface
1275
  * @v job		Job control interface
1190
  * @v netdev		Network device
1276
  * @v netdev		Network device
1191
- * @v pxe_server	PXE server (may be a multicast address)
1192
  * @v pxe_type		PXE server type
1277
  * @v pxe_type		PXE server type
1193
  * @ret rc		Return status code
1278
  * @ret rc		Return status code
1194
  *
1279
  *
1197
  * source.
1282
  * source.
1198
  */
1283
  */
1199
 int start_pxebs ( struct job_interface *job, struct net_device *netdev,
1284
 int start_pxebs ( struct job_interface *job, struct net_device *netdev,
1200
-		  struct in_addr pxe_server, unsigned int pxe_type ) {
1285
+		  unsigned int pxe_type ) {
1286
+	struct setting pxe_discovery_control_setting =
1287
+		{ .tag = DHCP_PXE_DISCOVERY_CONTROL };
1288
+	struct setting pxe_boot_servers_setting =
1289
+		{ .tag = DHCP_PXE_BOOT_SERVERS };
1290
+	struct setting pxe_boot_server_mcast_setting =
1291
+		{ .tag = DHCP_PXE_BOOT_SERVER_MCAST };
1292
+	ssize_t pxebs_list_len;
1201
 	struct dhcp_session *dhcp;
1293
 	struct dhcp_session *dhcp;
1294
+	struct in_addr *ip;
1295
+	unsigned int pxe_discovery_control;
1202
 	int rc;
1296
 	int rc;
1203
 
1297
 
1298
+	/* Get upper bound for PXE boot server IP address list */
1299
+	pxebs_list_len = fetch_setting_len ( NULL, &pxe_boot_servers_setting );
1300
+	if ( pxebs_list_len < 0 )
1301
+		pxebs_list_len = 0;
1302
+
1204
 	/* Allocate and initialise structure */
1303
 	/* Allocate and initialise structure */
1205
-	dhcp = zalloc ( sizeof ( *dhcp ) );
1304
+	dhcp = zalloc ( sizeof ( *dhcp ) + sizeof ( *ip ) /* mcast */ +
1305
+			sizeof ( *ip ) /* bcast */ + pxebs_list_len +
1306
+			sizeof ( *ip ) /* terminator */ );
1206
 	if ( ! dhcp )
1307
 	if ( ! dhcp )
1207
 		return -ENOMEM;
1308
 		return -ENOMEM;
1208
 	dhcp->refcnt.free = dhcp_free;
1309
 	dhcp->refcnt.free = dhcp_free;
1213
 	fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting,
1314
 	fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting,
1214
 			     &dhcp->local.sin_addr );
1315
 			     &dhcp->local.sin_addr );
1215
 	dhcp->local.sin_port = htons ( BOOTPC_PORT );
1316
 	dhcp->local.sin_port = htons ( BOOTPC_PORT );
1216
-	dhcp->pxe_server = pxe_server;
1217
 	dhcp->pxe_type = htons ( pxe_type );
1317
 	dhcp->pxe_type = htons ( pxe_type );
1218
 	dhcp->timer.expired = dhcp_timer_expired;
1318
 	dhcp->timer.expired = dhcp_timer_expired;
1219
 
1319
 
1320
+	/* Construct PXE boot server IP address lists */
1321
+	pxe_discovery_control =
1322
+		fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
1323
+	ip = ( ( ( void * ) dhcp ) + sizeof ( *dhcp ) );
1324
+	dhcp->pxe_attempt = ip;
1325
+	if ( ! ( pxe_discovery_control & PXEBS_NO_MULTICAST ) ) {
1326
+		fetch_ipv4_setting ( NULL, &pxe_boot_server_mcast_setting, ip);
1327
+		if ( ip->s_addr )
1328
+			ip++;
1329
+	}
1330
+	if ( ! ( pxe_discovery_control & PXEBS_NO_BROADCAST ) )
1331
+		(ip++)->s_addr = INADDR_BROADCAST;
1332
+	if ( pxe_discovery_control & PXEBS_NO_UNKNOWN_SERVERS )
1333
+		dhcp->pxe_accept = ip;
1334
+	if ( pxebs_list_len ) {
1335
+		uint8_t buf[pxebs_list_len];
1336
+
1337
+		fetch_setting ( NULL, &pxe_boot_servers_setting,
1338
+				buf, sizeof ( buf ) );
1339
+		pxebs_list ( dhcp, buf, sizeof ( buf ), ip );
1340
+	}
1341
+	if ( ! dhcp->pxe_attempt->s_addr ) {
1342
+		DBGC ( dhcp, "DHCP %p has no PXE boot servers for type %04x\n",
1343
+		       dhcp, pxe_type );
1344
+		rc = -EINVAL;
1345
+		goto err;
1346
+	}
1347
+
1348
+	/* Dump out PXE server lists */
1349
+	DBGC ( dhcp, "DHCP %p attempting", dhcp );
1350
+	for ( ip = dhcp->pxe_attempt ; ip->s_addr ; ip++ )
1351
+		DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
1352
+	DBGC ( dhcp, "\n" );
1353
+	if ( dhcp->pxe_accept ) {
1354
+		DBGC ( dhcp, "DHCP %p accepting", dhcp );
1355
+		for ( ip = dhcp->pxe_accept ; ip->s_addr ; ip++ )
1356
+			DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
1357
+		DBGC ( dhcp, "\n" );
1358
+	}
1359
+
1220
 	/* Instantiate child objects and attach to our interfaces */
1360
 	/* Instantiate child objects and attach to our interfaces */
1221
 	if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
1361
 	if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
1222
 				  ( struct sockaddr * ) &dhcp->local ) ) != 0 )
1362
 				  ( struct sockaddr * ) &dhcp->local ) ) != 0 )

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

47
 	return rc;
47
 	return rc;
48
 }
48
 }
49
 
49
 
50
-int pxebs ( struct net_device *netdev, struct in_addr pxe_server,
51
-	    unsigned int pxe_type ) {
50
+int pxebs ( struct net_device *netdev, unsigned int pxe_type ) {
52
 	int rc;
51
 	int rc;
53
 
52
 
54
 	/* Perform PXE Boot Server Discovery */
53
 	/* Perform PXE Boot Server Discovery */
55
-	printf ( "PXEBS (%s %s type %d)",
56
-		 netdev->name, inet_ntoa ( pxe_server ), pxe_type );
57
-	if ( ( rc = start_pxebs ( &monojob, netdev, pxe_server,
58
-				  pxe_type ) ) == 0 )
54
+	printf ( "PXEBS (%s type %d)", netdev->name, pxe_type );
55
+	if ( ( rc = start_pxebs ( &monojob, netdev, pxe_type ) ) == 0 )
59
 		rc = monojob_wait ( "" );
56
 		rc = monojob_wait ( "" );
60
 
57
 
61
 	return rc;
58
 	return rc;

+ 1
- 11
src/usr/pxemenu.c View File

57
  * options.
57
  * options.
58
  */
58
  */
59
 struct pxe_menu {
59
 struct pxe_menu {
60
-	/** Boot Server address */
61
-	struct in_addr server;
62
 	/** Timeout (in seconds)
60
 	/** Timeout (in seconds)
63
 	 *
61
 	 *
64
 	 * Negative indicates no timeout (i.e. wait indefinitely)
62
 	 * Negative indicates no timeout (i.e. wait indefinitely)
83
  */
81
  */
84
 static int pxe_menu_parse ( struct pxe_menu **menu ) {
82
 static int pxe_menu_parse ( struct pxe_menu **menu ) {
85
 	struct setting tmp_setting = { .name = NULL };
83
 	struct setting tmp_setting = { .name = NULL };
86
-	struct in_addr server;
87
 	struct dhcp_pxe_boot_menu_prompt prompt = { .timeout = 0 };
84
 	struct dhcp_pxe_boot_menu_prompt prompt = { .timeout = 0 };
88
 	uint8_t raw_menu[256];
85
 	uint8_t raw_menu[256];
89
 	int raw_menu_len;
86
 	int raw_menu_len;
94
 	int rc;
91
 	int rc;
95
 
92
 
96
 	/* Fetch relevant settings */
93
 	/* Fetch relevant settings */
97
-	tmp_setting.tag = DHCP_PXE_BOOT_SERVER_MCAST;
98
-	fetch_ipv4_setting ( NULL, &tmp_setting, &server );
99
-	if ( ! server.s_addr )
100
-		server.s_addr = INADDR_BROADCAST;
101
 	tmp_setting.tag = DHCP_PXE_BOOT_MENU_PROMPT;
94
 	tmp_setting.tag = DHCP_PXE_BOOT_MENU_PROMPT;
102
 	fetch_setting ( NULL, &tmp_setting, &prompt, sizeof ( prompt ) );
95
 	fetch_setting ( NULL, &tmp_setting, &prompt, sizeof ( prompt ) );
103
 	tmp_setting.tag = DHCP_PXE_BOOT_MENU;
96
 	tmp_setting.tag = DHCP_PXE_BOOT_MENU;
142
 	}
135
 	}
143
 
136
 
144
 	/* Fill in parsed menu */
137
 	/* Fill in parsed menu */
145
-	(*menu)->server = server;
146
 	(*menu)->timeout =
138
 	(*menu)->timeout =
147
 		( ( prompt.timeout == 0xff ) ? -1 : prompt.timeout );
139
 		( ( prompt.timeout == 0xff ) ? -1 : prompt.timeout );
148
 	(*menu)->num_items = num_menu_items;
140
 	(*menu)->num_items = num_menu_items;
296
  */
288
  */
297
 int pxe_menu_boot ( struct net_device *netdev ) {
289
 int pxe_menu_boot ( struct net_device *netdev ) {
298
 	struct pxe_menu *menu;
290
 	struct pxe_menu *menu;
299
-	struct in_addr pxe_server;
300
 	unsigned int pxe_type;
291
 	unsigned int pxe_type;
301
 	struct settings *pxebs_settings;
292
 	struct settings *pxebs_settings;
302
 	struct in_addr next_server;
293
 	struct in_addr next_server;
312
 		free ( menu );
303
 		free ( menu );
313
 		return rc;
304
 		return rc;
314
 	}
305
 	}
315
-	pxe_server = menu->server;
316
 	pxe_type = menu->items[menu->selection].type;
306
 	pxe_type = menu->items[menu->selection].type;
317
 
307
 
318
 	/* Free boot menu */
308
 	/* Free boot menu */
323
 		return 0;
313
 		return 0;
324
 
314
 
325
 	/* Attempt PXE Boot Server Discovery */
315
 	/* Attempt PXE Boot Server Discovery */
326
-	if ( ( rc = pxebs ( netdev, pxe_server, pxe_type ) ) != 0 )
316
+	if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 )
327
 		return rc;
317
 		return rc;
328
 
318
 
329
 	/* Attempt boot */
319
 	/* Attempt boot */

Loading…
Cancel
Save