[ipxe-devel] [PATCH 02/11] dhcpv6: Fallback to using DUID-LL for empty UUID

Hannes Reinecke hare at suse.de
Thu May 7 09:24:57 UTC 2015


If the system UUID is empty we cannot use it as a
DUID for DCHPv6.
So fallback to use DUID-LL in these cases.

Signed-off-by: Hannes Reinecke <hare at suse.de>
---
 src/core/uuid.c           |  2 ++
 src/include/ipxe/dhcpv6.h | 13 +++++++++++++
 src/include/ipxe/uuid.h   |  2 ++
 src/net/udp/dhcpv6.c      | 28 +++++++++++++++++++++-------
 4 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/src/core/uuid.c b/src/core/uuid.c
index b8d21de..5992232 100644
--- a/src/core/uuid.c
+++ b/src/core/uuid.c
@@ -34,6 +34,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  *
  */
 
+const union uuid null_uuid;
+
 /**
  * Convert UUID to printable string
  *
diff --git a/src/include/ipxe/dhcpv6.h b/src/include/ipxe/dhcpv6.h
index 9307b6c..5d0b657 100644
--- a/src/include/ipxe/dhcpv6.h
+++ b/src/include/ipxe/dhcpv6.h
@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 #include <stdint.h>
 #include <ipxe/in.h>
+#include <ipxe/if_ether.h>
 #include <ipxe/uuid.h>
 
 /** DHCPv6 server port */
@@ -32,6 +33,16 @@ struct dhcpv6_option {
 	uint8_t data[0];
 } __attribute__ (( packed ));
 
+/** DHCP unique identifier based on Ethernet Link-layer address (DUID-LL) */
+struct dhcpv6_duid_eth_ll {
+	/** Type */
+	uint16_t type;
+	/** Hardware type: Ethernet */
+	uint16_t hw_type;
+	/** Ethernet link-layer address */
+	uint8_t ll_addr[ETH_ALEN];
+} __attribute__ (( packed ));
+
 /** DHCP unique identifier based on UUID (DUID-UUID) */
 struct dhcpv6_duid_uuid {
 	/** Type */
@@ -40,6 +51,8 @@ struct dhcpv6_duid_uuid {
 	union uuid uuid;
 } __attribute__ (( packed ));
 
+/** DHCP unique identifier based on link-layer address (DUID-LL) */
+#define DHCPV6_DUID_LL 3
 /** DHCP unique identifier based on UUID (DUID-UUID) */
 #define DHCPV6_DUID_UUID 4
 
diff --git a/src/include/ipxe/uuid.h b/src/include/ipxe/uuid.h
index 6c45eb9..7f16b38 100644
--- a/src/include/ipxe/uuid.h
+++ b/src/include/ipxe/uuid.h
@@ -49,4 +49,6 @@ static inline void uuid_mangle ( union uuid *uuid ) {
 
 extern char * uuid_ntoa ( const union uuid *uuid );
 
+extern const union uuid null_uuid;
+
 #endif /* _IPXE_UUID_H */
diff --git a/src/net/udp/dhcpv6.c b/src/net/udp/dhcpv6.c
index a635437..e3953d2 100644
--- a/src/net/udp/dhcpv6.c
+++ b/src/net/udp/dhcpv6.c
@@ -462,7 +462,11 @@ struct dhcpv6_session {
 	/** Start time (in ticks) */
 	unsigned long start;
 	/** Client DUID */
-	struct dhcpv6_duid_uuid client_duid;
+	union {
+		struct dhcpv6_duid_uuid uuid;
+		struct dhcpv6_duid_eth_ll ll;
+	} client_duid;
+	int client_duid_len;
 	/** Server DUID, if known */
 	void *server_duid;
 	/** Server DUID length */
@@ -582,7 +586,7 @@ static int dhcpv6_tx ( struct dhcpv6_session *dhcpv6 ) {
 
 	/* Calculate lengths */
 	client_id_len = ( sizeof ( *client_id ) +
-			  sizeof ( dhcpv6->client_duid ) );
+			  dhcpv6->client_duid_len );
 	server_id_len = ( dhcpv6->server_duid ? ( sizeof ( *server_id ) +
 						  dhcpv6->server_duid_len ) :0);
 	if ( dhcpv6->state->flags & DHCPV6_TX_IA_NA ) {
@@ -619,7 +623,7 @@ static int dhcpv6_tx ( struct dhcpv6_session *dhcpv6 ) {
 	client_id->header.len = htons ( client_id_len -
 					sizeof ( client_id->header ) );
 	memcpy ( client_id->duid, &dhcpv6->client_duid,
-		 sizeof ( dhcpv6->client_duid ) );
+		 dhcpv6->client_duid_len );
 
 	/* Construct server identifier, if applicable */
 	if ( server_id_len ) {
@@ -753,7 +757,7 @@ static int dhcpv6_rx ( struct dhcpv6_session *dhcpv6,
 	/* Verify client identifier */
 	if ( ( rc = dhcpv6_check_duid ( &options, DHCPV6_CLIENT_ID,
 					&dhcpv6->client_duid,
-					sizeof ( dhcpv6->client_duid ) ) ) !=0){
+					dhcpv6->client_duid_len ) ) !=0){
 		DBGC ( dhcpv6, "DHCPv6 %s received %s without correct client "
 		       "ID: %s\n", dhcpv6->netdev->name,
 		       dhcpv6_type_name ( dhcphdr->type ), strerror ( rc ) );
@@ -935,15 +939,25 @@ int start_dhcpv6 ( struct interface *job, struct net_device *netdev,
 	addresses.server.sin6.sin6_port = htons ( DHCPV6_SERVER_PORT );
 
 	/* Construct client DUID from system UUID */
-	dhcpv6->client_duid.type = htons ( DHCPV6_DUID_UUID );
+	dhcpv6->client_duid_len = sizeof(struct dhcpv6_duid_uuid);
+	dhcpv6->client_duid.uuid.type = htons ( DHCPV6_DUID_UUID );
 	if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting,
-					  &dhcpv6->client_duid.uuid ) ) < 0 ) {
+					  &dhcpv6->client_duid.uuid.uuid ) ) <= 0 ) {
 		rc = len;
 		DBGC ( dhcpv6, "DHCPv6 %s could not create DUID-UUID: %s\n",
 		       dhcpv6->netdev->name, strerror ( rc ) );
 		goto err_client_duid;
 	}
-
+	if (!memcmp( &dhcpv6->client_duid.uuid.uuid, &null_uuid,
+		     sizeof(null_uuid) )) {
+		DBGC ( dhcpv6, "DHCPv6 %s empty DUID-UUID, using DUID-LL\n",
+		       dhcpv6->netdev->name );
+		dhcpv6->client_duid.ll.type = htons ( DHCPV6_DUID_LL );
+		dhcpv6->client_duid.ll.hw_type = ll_protocol->ll_proto;
+		memcpy( dhcpv6->client_duid.ll.ll_addr, netdev->ll_addr,
+			ll_protocol->ll_addr_len );
+		dhcpv6->client_duid_len = sizeof(struct dhcpv6_duid_eth_ll);
+	}
 	/* Construct IAID from link-layer address */
 	dhcpv6->iaid = crc32_le ( 0, netdev->ll_addr, ll_protocol->ll_addr_len);
 	DBGC ( dhcpv6, "DHCPv6 %s has XID %02x%02x%02x\n", dhcpv6->netdev->name,
-- 
1.8.4.5




More information about the ipxe-devel mailing list