708deb9
From 66eac1201a9c1596f5901f8dbbf24bda7e350878 Mon Sep 17 00:00:00 2001
708deb9
From: Dan Williams <dcbw@redhat.com>
708deb9
Date: Fri, 26 Sep 2014 15:12:36 -0500
708deb9
Subject: [PATCH] sd-dhcp6-client: support custom DUIDs
708deb9
708deb9
The caller may have an existing DUID that it wants to use, and may
708deb9
want to use some other DUID generation scheme than systemd's
708deb9
default DUID-EN.
708deb9
708deb9
[tomegun: whitespace - we never use tabs]
708deb9
---
708deb9
 src/libsystemd-network/sd-dhcp6-client.c | 43 +++++++++++++++++++++++---------
708deb9
 src/systemd/sd-dhcp6-client.h            |  2 ++
708deb9
 2 files changed, 33 insertions(+), 12 deletions(-)
708deb9
708deb9
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
708deb9
index c190b560ea..130fe43cf2 100644
708deb9
--- a/src/libsystemd-network/sd-dhcp6-client.c
708deb9
+++ b/src/libsystemd-network/sd-dhcp6-client.c
708deb9
@@ -39,6 +39,8 @@
708deb9
 #define SYSTEMD_PEN 43793
708deb9
 #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
708deb9
 
708deb9
+#define MAX_DUID_LEN 32
708deb9
+
708deb9
 struct sd_dhcp6_client {
708deb9
         RefCount n_ref;
708deb9
 
708deb9
@@ -62,12 +64,8 @@ struct sd_dhcp6_client {
708deb9
         sd_event_source *timeout_resend_expire;
708deb9
         sd_dhcp6_client_cb_t cb;
708deb9
         void *userdata;
708deb9
-
708deb9
-        struct duid_en {
708deb9
-                uint16_t type; /* DHCP6_DUID_EN */
708deb9
-                uint32_t pen;
708deb9
-                uint8_t id[8];
708deb9
-        } _packed_ duid;
708deb9
+        uint8_t duid[MAX_DUID_LEN];
708deb9
+        size_t duid_len;
708deb9
 };
708deb9
 
708deb9
 static const uint16_t default_req_opts[] = {
708deb9
@@ -147,6 +145,19 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
708deb9
         return 0;
708deb9
 }
708deb9
 
708deb9
+int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint8_t *duid,
708deb9
+                             size_t duid_len)
708deb9
+{
708deb9
+        assert_return(client, -EINVAL);
708deb9
+        assert_return(duid, -EINVAL);
708deb9
+        assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL);
708deb9
+
708deb9
+        memcpy(&client->duid, duid, duid_len);
708deb9
+        client->duid_len = duid_len;
708deb9
+
708deb9
+        return 0;
708deb9
+}
708deb9
+
708deb9
 int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
708deb9
                                        uint16_t option) {
708deb9
         size_t t;
708deb9
@@ -308,7 +319,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
708deb9
                 return r;
708deb9
 
708deb9
         r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
708deb9
-                                sizeof(client->duid), &client->duid);
708deb9
+                                client->duid_len, &client->duid);
708deb9
         if (r < 0)
708deb9
                 return r;
708deb9
 
708deb9
@@ -616,7 +627,7 @@ static int client_parse_message(sd_dhcp6_client *client,
708deb9
                                 return -EINVAL;
708deb9
                         }
708deb9
 
708deb9
-                        if (optlen != sizeof(client->duid) ||
708deb9
+                        if (optlen != client->duid_len ||
708deb9
                             memcmp(&client->duid, optval, optlen) != 0) {
708deb9
                                 log_dhcp6_client(client, "%s DUID does not match",
708deb9
                                                  dhcp6_message_type_to_string(message->type));
708deb9
@@ -1116,9 +1127,16 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
708deb9
         return client;
708deb9
 }
708deb9
 
708deb9
+struct duid_en {
708deb9
+        uint16_t type; /* DHCP6_DUID_EN */
708deb9
+        uint32_t pen;
708deb9
+        uint8_t id[8];
708deb9
+} _packed_;
708deb9
+
708deb9
 int sd_dhcp6_client_new(sd_dhcp6_client **ret)
708deb9
 {
708deb9
         _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL;
708deb9
+        struct duid_en *duid;
708deb9
         sd_id128_t machine_id;
708deb9
         int r;
708deb9
         size_t t;
708deb9
@@ -1138,8 +1156,9 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
708deb9
         client->fd = -1;
708deb9
 
708deb9
         /* initialize DUID */
708deb9
-        client->duid.type = htobe16(DHCP6_DUID_EN);
708deb9
-        client->duid.pen = htobe32(SYSTEMD_PEN);
708deb9
+        duid = (struct duid_en *) &client->duid;
708deb9
+        duid->type = htobe16(DHCP6_DUID_EN);
708deb9
+        duid->pen = htobe32(SYSTEMD_PEN);
708deb9
 
708deb9
         r = sd_id128_get_machine(&machine_id);
708deb9
         if (r < 0)
708deb9
@@ -1147,8 +1166,8 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
708deb9
 
708deb9
         /* a bit of snake-oil perhaps, but no need to expose the machine-id
708deb9
            directly */
708deb9
-        siphash24(client->duid.id, &machine_id, sizeof(machine_id),
708deb9
-                  HASH_KEY.bytes);
708deb9
+        siphash24(duid->id, &machine_id, sizeof(machine_id), HASH_KEY.bytes);
708deb9
+        client->duid_len = sizeof (struct duid_en);
708deb9
 
708deb9
         client->req_opts_len = ELEMENTSOF(default_req_opts);
708deb9
 
708deb9
diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
708deb9
index 93edcc41fc..7b7f098b0c 100644
708deb9
--- a/src/systemd/sd-dhcp6-client.h
708deb9
+++ b/src/systemd/sd-dhcp6-client.h
708deb9
@@ -45,6 +45,8 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
708deb9
 int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
708deb9
 int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
708deb9
                             const struct ether_addr *mac_addr);
708deb9
+int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint8_t *duid,
708deb9
+                             size_t duid_len);
708deb9
 int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
708deb9
                                        uint16_t option);
708deb9