Provide a function to request more options from the DHCPv6 server.
Provide a sensible default set at startup and add test basic test
cases for the intended usage.

Define DNS and NTP related option codes and add comments for the
unassigned codes.
---
 src/libsystemd-network/dhcp6-protocol.h    | 12 +++++++
 src/libsystemd-network/sd-dhcp6-client.c   | 57 ++++++++++++++++++++++++++++++
 src/libsystemd-network/test-dhcp6-client.c |  9 +++++
 src/systemd/sd-dhcp6-client.h              |  2 ++
 4 files changed, 80 insertions(+)

diff --git a/src/libsystemd-network/dhcp6-protocol.h 
b/src/libsystemd-network/dhcp6-protocol.h
index 8b3a819..37a8671 100644
--- a/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/libsystemd-network/dhcp6-protocol.h
@@ -111,6 +111,18 @@ enum {
         DHCP6_OPTION_INTERFACE_ID               = 18,
         DHCP6_OPTION_RECONF_MSG                 = 19,
         DHCP6_OPTION_RECONF_ACCEPT              = 20,
+
+        DHCP6_OPTION_DNS_SERVERS                = 23,  /* RFC 3646 */
+        DHCP6_OPTION_DOMAIN_LIST                = 24,  /* RFC 3646 */
+
+        DHCP6_OPTION_SNTP_SERVERS               = 31,  /* RFC 4075 */
+
+        /* option code 35 is unassigned */
+
+        DHCP6_OPTION_NTP_SERVER                 = 56,  /* RFC 5908 */
+
+        /* option codes 89-142 are unassigned */
+        /* option codes 144-65535 are unassigned */
 };
 
 enum {
diff --git a/src/libsystemd-network/sd-dhcp6-client.c 
b/src/libsystemd-network/sd-dhcp6-client.c
index 928f562..f6709da 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -51,6 +51,9 @@ struct sd_dhcp6_client {
         be32_t transaction_id;
         struct sd_dhcp6_lease *lease;
         int fd;
+        be16_t *req_opts;
+        size_t req_opts_allocated;
+        size_t req_opts_len;
         sd_event_source *receive_message;
         usec_t retransmit_time;
         uint8_t retransmit_count;
@@ -66,6 +69,12 @@ struct sd_dhcp6_client {
         } _packed_ duid;
 };
 
+static const uint16_t default_req_opts[] = {
+        DHCP6_OPTION_DNS_SERVERS,
+        DHCP6_OPTION_DOMAIN_LIST,
+        DHCP6_OPTION_NTP_SERVER,
+};
+
 const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
         [DHCP6_SOLICIT] = "SOLICIT",
         [DHCP6_ADVERTISE] = "ADVERTISE",
@@ -137,6 +146,37 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
         return 0;
 }
 
+int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
+                                       uint16_t option) {
+        size_t t;
+
+        assert_return(client, -EINVAL);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
+
+        switch(option) {
+        case DHCP6_OPTION_DNS_SERVERS:
+        case DHCP6_OPTION_DOMAIN_LIST:
+        case DHCP6_OPTION_SNTP_SERVERS:
+        case DHCP6_OPTION_NTP_SERVER:
+                break;
+
+        default:
+                return -EINVAL;
+        }
+
+        for (t = 0; t < client->req_opts_len; t++)
+                if (client->req_opts[t] == htobe16(option))
+                        return -EEXIST;
+
+        if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
+                            (client->req_opts_len + 1) * sizeof(option)))
+                return -ENOMEM;
+
+        client->req_opts[client->req_opts_len++] = htobe16(option);
+
+        return 0;
+}
+
 int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
         assert_return(client, -EINVAL);
         assert_return(ret, -EINVAL);
@@ -239,6 +279,12 @@ static int client_send_message(sd_dhcp6_client *client) {
                 return -EINVAL;
         }
 
+        r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ORO,
+                                client->req_opts_len * sizeof(be16_t),
+                                client->req_opts);
+        if (r < 0)
+                return r;
+
         r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
                                 sizeof(client->duid), &client->duid);
         if (r < 0)
@@ -927,6 +973,7 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client 
*client) {
 
                 sd_dhcp6_client_detach_event(client);
 
+                free(client->req_opts);
                 free(client);
 
                 return NULL;
@@ -940,6 +987,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
         _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL;
         sd_id128_t machine_id;
         int r;
+        size_t t;
 
         assert_return(ret, -EINVAL);
 
@@ -968,6 +1016,15 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
         siphash24(client->duid.id, &machine_id, sizeof(machine_id),
                   HASH_KEY.bytes);
 
+        client->req_opts_len = ELEMENTSOF(default_req_opts);
+
+        client->req_opts = new0(be16_t, client->req_opts_len);
+        if (!client->req_opts)
+                return -ENOMEM;
+
+        for (t = 0; t < client->req_opts_len; t++)
+                client->req_opts[t] = htobe16(default_req_opts[t]);
+
         *ret = client;
         client = NULL;
 
diff --git a/src/libsystemd-network/test-dhcp6-client.c 
b/src/libsystemd-network/test-dhcp6-client.c
index c5729db..5bb410d 100644
--- a/src/libsystemd-network/test-dhcp6-client.c
+++ b/src/libsystemd-network/test-dhcp6-client.c
@@ -68,6 +68,13 @@ static int test_client_basic(sd_event *e) {
 
         assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
 
+        assert_se(sd_dhcp6_client_set_request_option(client, 
DHCP6_OPTION_CLIENTID) == -EINVAL);
+        assert_se(sd_dhcp6_client_set_request_option(client, 
DHCP6_OPTION_DNS_SERVERS) == -EEXIST);
+        assert_se(sd_dhcp6_client_set_request_option(client, 
DHCP6_OPTION_NTP_SERVER) == -EEXIST);
+        assert_se(sd_dhcp6_client_set_request_option(client, 
DHCP6_OPTION_SNTP_SERVERS) == 0);
+        assert_se(sd_dhcp6_client_set_request_option(client, 
DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
+        assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
+
         assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
 
         assert_se(sd_dhcp6_client_detach_event(client) >= 0);
@@ -520,6 +527,8 @@ static void test_client_solicit_cb(sd_dhcp6_client *client, 
int event,
         assert_se(e);
         assert_se(event == DHCP6_EVENT_IP_ACQUIRE);
 
+        assert_se(sd_dhcp6_client_set_request_option(client, 
DHCP6_OPTION_DNS_SERVERS) == -EBUSY);
+
         if (verbose)
                 printf("  got DHCPv6 event %d\n", event);
 
diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
index 15e633b..93edcc4 100644
--- a/src/systemd/sd-dhcp6-client.h
+++ b/src/systemd/sd-dhcp6-client.h
@@ -45,6 +45,8 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
 int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
 int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
                             const struct ether_addr *mac_addr);
+int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
+                                       uint16_t option);
 
 int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret);
 
-- 
1.9.1

_______________________________________________
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel

Reply via email to