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
 /** Setting block name used for BootServerDHCP responses */
620
 /** Setting block name used for BootServerDHCP responses */
621
 #define PXEBS_SETTINGS_NAME "pxebs"
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
 extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
625
 extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
626
 				struct net_device *netdev, uint8_t msgtype,
626
 				struct net_device *netdev, uint8_t msgtype,
627
 				const void *options, size_t options_len,
627
 				const void *options, size_t options_len,

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

867
  * Construct DHCP client hardware address field and broadcast flag
867
  * Construct DHCP client hardware address field and broadcast flag
868
  *
868
  *
869
  * @v netdev		Network device
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
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
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
 	/* If the link-layer address cannot fit into the chaddr field
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
 	 * If even the hardware address is too large, use an empty
889
 	 * If even the hardware address is too large, use an empty
886
 	 * chaddr field and set the broadcast flag.
890
 	 * chaddr field and set the broadcast flag.
891
 	 * storage, or by eliminating the hardware address completely
895
 	 * storage, or by eliminating the hardware address completely
892
 	 * from the DHCP packet, which seems unfriendly to users.
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
 			 const void *options, size_t options_len,
930
 			 const void *options, size_t options_len,
924
 			 void *data, size_t max_len ) {
931
 			 void *data, size_t max_len ) {
925
 	struct dhcphdr *dhcphdr = data;
932
 	struct dhcphdr *dhcphdr = data;
926
-	void *chaddr;
927
 	int rc;
933
 	int rc;
928
 
934
 
929
 	/* Sanity check */
935
 	/* Sanity check */
936
 	dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
942
 	dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
937
 	dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
943
 	dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
938
 	dhcphdr->op = dhcp_op[msgtype];
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
 	memcpy ( dhcphdr->options, options, options_len );
947
 	memcpy ( dhcphdr->options, options, options_len );
942
 
948
 
943
 	/* Initialise DHCP packet structure */
949
 	/* Initialise DHCP packet structure */

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

37
  */
37
  */
38
 
38
 
39
 int dhcp ( struct net_device *netdev ) {
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
 	int rc;
44
 	int rc;
44
 
45
 
45
 	/* Check we can open the interface first */
46
 	/* Check we can open the interface first */
51
 		return rc;
52
 		return rc;
52
 
53
 
53
 	/* Perform DHCP */
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
 	if ( ( rc = start_dhcp ( &monojob, netdev ) ) == 0 ) {
61
 	if ( ( rc = start_dhcp ( &monojob, netdev ) ) == 0 ) {
60
 		rc = monojob_wait ( "" );
62
 		rc = monojob_wait ( "" );

Loading…
Cancel
Save