Browse Source

[dhcp] Use Ethernet-compatible chaddr, if possible

For IPoIB, we currently use the hardware address (i.e. the eight-byte
GUID) as the DHCP chaddr.  This works, but some PXE servers (notably
Altiris RDP) refuse to respond if the chaddr field is anything other
than six bytes in length.

We already have the notion of an Ethernet-compatible link-layer
address, which is used in the iBFT (the design of which similarly
fails to account for non-Ethernet link layers).  Use this as the first
preferred alternative to the actual link-layer address when
constructing the DHCP chaddr field.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
708c5060b9
3 changed files with 38 additions and 30 deletions
  1. 2
    2
      src/include/ipxe/dhcp.h
  2. 27
    21
      src/net/udp/dhcp.c
  3. 9
    7
      src/usr/dhcpmgmt.c

+ 2
- 2
src/include/ipxe/dhcp.h View File

@@ -620,8 +620,8 @@ struct dhcphdr {
620 620
 /** Setting block name used for BootServerDHCP responses */
621 621
 #define PXEBS_SETTINGS_NAME "pxebs"
622 622
 
623
-extern void * dhcp_chaddr ( struct net_device *netdev, uint8_t *hlen,
624
-			    uint16_t *flags );
623
+extern unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
624
+				  uint16_t *flags );
625 625
 extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
626 626
 				struct net_device *netdev, uint8_t msgtype,
627 627
 				const void *options, size_t options_len,

+ 27
- 21
src/net/udp/dhcp.c View File

@@ -867,20 +867,24 @@ static struct dhcp_session_state dhcp_state_pxebs = {
867 867
  * Construct DHCP client hardware address field and broadcast flag
868 868
  *
869 869
  * @v netdev		Network device
870
- * @v hlen		DHCP hardware address length to fill in
871
- * @v flags		DHCP flags to fill in
872
- * @ret chaddr		DHCP client hardware address
870
+ * @v chaddr		Hardware address buffer
871
+ * @v flags		Flags to set (or NULL)
872
+ * @ret hlen		Hardware address length
873 873
  */
874
-void * dhcp_chaddr ( struct net_device *netdev, uint8_t *hlen,
875
-		     uint16_t *flags ) {
874
+unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
875
+			   uint16_t *flags ) {
876 876
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
877
-	typeof ( ( ( struct dhcphdr * ) NULL )->chaddr ) chaddr;
877
+	struct dhcphdr *dhcphdr;
878
+	int rc;
878 879
 
879 880
 	/* If the link-layer address cannot fit into the chaddr field
880
-	 * (as is the case for IPoIB) then try using the hardware
881
-	 * address instead.  If we do this, set the broadcast flag,
882
-	 * since chaddr then does not represent a valid link-layer
883
-	 * address for the return path.
881
+	 * (as is the case for IPoIB) then try using the Ethernet-
882
+	 * compatible link-layer address.  If we do this, set the
883
+	 * broadcast flag, since chaddr then does not represent a
884
+	 * valid link-layer address for the return path.
885
+	 *
886
+	 * If we cannot produce an Ethernet-compatible link-layer
887
+	 * address, try using the hardware address.
884 888
 	 *
885 889
 	 * If even the hardware address is too large, use an empty
886 890
 	 * chaddr field and set the broadcast flag.
@@ -891,16 +895,19 @@ void * dhcp_chaddr ( struct net_device *netdev, uint8_t *hlen,
891 895
 	 * storage, or by eliminating the hardware address completely
892 896
 	 * from the DHCP packet, which seems unfriendly to users.
893 897
 	 */
894
-	if ( ( *hlen = ll_protocol->ll_addr_len ) <= sizeof ( chaddr ) ) {
895
-		return netdev->ll_addr;
898
+	if ( ll_protocol->ll_addr_len <= sizeof ( dhcphdr->chaddr ) ) {
899
+		memcpy ( chaddr, netdev->ll_addr, ll_protocol->ll_addr_len );
900
+		return ll_protocol->ll_addr_len;
896 901
 	}
897
-	*flags = htons ( BOOTP_FL_BROADCAST );
898
-	if ( ( *hlen = ll_protocol->hw_addr_len ) <= sizeof ( chaddr ) ) {
899
-		return netdev->hw_addr;
900
-	} else {
901
-		*hlen = 0;
902
-		return NULL;
902
+	if ( flags )
903
+		*flags |= htons ( BOOTP_FL_BROADCAST );
904
+	if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr, chaddr ) ) == 0 )
905
+		return ETH_ALEN;
906
+	if ( ll_protocol->hw_addr_len <= sizeof ( dhcphdr->chaddr ) ) {
907
+		memcpy ( chaddr, netdev->hw_addr, ll_protocol->hw_addr_len );
908
+		return ll_protocol->hw_addr_len;
903 909
 	}
910
+	return 0;
904 911
 }
905 912
 
906 913
 /**
@@ -923,7 +930,6 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
923 930
 			 const void *options, size_t options_len,
924 931
 			 void *data, size_t max_len ) {
925 932
 	struct dhcphdr *dhcphdr = data;
926
-	void *chaddr;
927 933
 	int rc;
928 934
 
929 935
 	/* Sanity check */
@@ -936,8 +942,8 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
936 942
 	dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
937 943
 	dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
938 944
 	dhcphdr->op = dhcp_op[msgtype];
939
-	chaddr = dhcp_chaddr ( netdev, &dhcphdr->hlen, &dhcphdr->flags );
940
-	memcpy ( dhcphdr->chaddr, chaddr, dhcphdr->hlen );
945
+	dhcphdr->hlen = dhcp_chaddr ( netdev, dhcphdr->chaddr,
946
+				      &dhcphdr->flags );
941 947
 	memcpy ( dhcphdr->options, options, options_len );
942 948
 
943 949
 	/* Initialise DHCP packet structure */

+ 9
- 7
src/usr/dhcpmgmt.c View File

@@ -37,9 +37,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
37 37
  */
38 38
 
39 39
 int dhcp ( struct net_device *netdev ) {
40
-	uint8_t *chaddr;
41
-	uint8_t hlen;
42
-	uint16_t flags;
40
+	struct dhcphdr *dhcphdr;
41
+	typeof ( dhcphdr->chaddr ) chaddr;
42
+	unsigned int hlen;
43
+	unsigned int i;
43 44
 	int rc;
44 45
 
45 46
 	/* Check we can open the interface first */
@@ -51,10 +52,11 @@ int dhcp ( struct net_device *netdev ) {
51 52
 		return rc;
52 53
 
53 54
 	/* Perform DHCP */
54
-	chaddr = dhcp_chaddr ( netdev, &hlen, &flags );
55
-	printf ( "DHCP (%s ", netdev->name );
56
-	while ( hlen-- )
57
-		printf ( "%02x%c", *(chaddr++), ( hlen ? ':' : ')' ) );
55
+	printf ( "DHCP (%s", netdev->name );
56
+	hlen = dhcp_chaddr ( netdev, chaddr, NULL );
57
+	for ( i = 0 ; i < hlen ; i++ )
58
+		printf ( "%c%02x", ( i ? ':' : ' ' ), chaddr[i] );
59
+	printf ( ")" );
58 60
 
59 61
 	if ( ( rc = start_dhcp ( &monojob, netdev ) ) == 0 ) {
60 62
 		rc = monojob_wait ( "" );

Loading…
Cancel
Save