diff --git a/clients/cli/generate-docs-nm-settings-nmcli.xml.in b/clients/cli/generate-docs-nm-settings-nmcli.xml.in
index a4e6715cc8..f269af0646 100644
--- a/clients/cli/generate-docs-nm-settings-nmcli.xml.in
+++ b/clients/cli/generate-docs-nm-settings-nmcli.xml.in
@@ -652,7 +652,7 @@
+ description="A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values "mac" and "perm-mac" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value "ipv6-duid" uses the DUID from "ipv6.dhcp-duid" property as an RFC4361-compliant client identifier. As IAID it uses "ipv4.dhcp-iaid" and falls back to "ipv6.dhcp-iaid" if unset. The special value "duid" generates a RFC4361-compliant client identifier based on "ipv4.dhcp-iaid" and uses a DUID generated by hashing /etc/machine-id. The special value "stable" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the "${DEVICE}" or "${MAC}" specifier to get a per-device key. If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin." />
= 2u + 1u);
+ nm_assert(duid_len <= 2u + 128u);
+
+ result = nm_utils_dhcp_client_id_duid(iaid, duid_arr, duid_len);
+ goto out_good;
+ }
+
if (nm_streq(client_id, "stable")) {
nm_auto_free_checksum GChecksum *sum = NULL;
guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1];
@@ -9802,7 +9835,7 @@ dhcp6_start_with_link_ready(NMDevice *self, NMConnection *connection)
if (pllink)
hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address);
- iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, &iaid_explicit);
+ iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, TRUE, &iaid_explicit);
duid = _prop_get_ipv6_dhcp_duid(self, connection, hwaddr, &enforce_duid);
priv->dhcp_data_6.client = nm_dhcp_manager_start_ip6(
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index 9df960ac3c..7b62968fb5 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -4035,6 +4035,30 @@ nm_utils_create_dhcp_iaid(gboolean legacy_unstable_byteorder,
}
}
+GBytes *
+nm_utils_dhcp_client_id_duid(guint32 iaid, const guint8 *duid, gsize duid_len)
+{
+ struct _nm_packed {
+ guint8 type;
+ guint32 iaid;
+ guint8 duid[];
+ } * client_id;
+ gsize total_size;
+
+ /* the @duid must include the 16 bit duid-type and the data (of max 128 bytes). */
+ g_return_val_if_fail(duid_len > 2 && duid_len < 128 + 2, NULL);
+ g_return_val_if_fail(duid, NULL);
+
+ total_size = sizeof(*client_id) + duid_len;
+
+ client_id = g_malloc(total_size);
+
+ client_id->type = 255;
+ unaligned_write_be32(&client_id->iaid, iaid);
+ memcpy(client_id->duid, duid, duid_len);
+ return g_bytes_new_take(client_id, total_size);
+}
+
/**
* nm_utils_dhcp_client_id_systemd_node_specific_full:
* @iaid: the IAID (identity association identifier) in native byte order
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
index a5244f5d8c..c90daaa683 100644
--- a/src/nm-core-utils.h
+++ b/src/nm-core-utils.h
@@ -449,6 +449,8 @@ guint32 nm_utils_create_dhcp_iaid(gboolean legacy_unstable_byteorder,
const guint8 *interface_id,
gsize interface_id_len);
+GBytes *nm_utils_dhcp_client_id_duid(guint32 iaid, const guint8 *duid, gsize duid_len);
+
GBytes *nm_utils_dhcp_client_id_systemd_node_specific_full(guint32 iaid,
const guint8 *machine_id,
gsize machine_id_len);