[systemd-commits] 8 commits - TODO src/libsystemd-network src/network src/systemd

Patrik Flykt pflykt at kemper.freedesktop.org
Thu Jun 26 06:12:07 PDT 2014


 TODO                                          |   16 ++
 src/libsystemd-network/dhcp6-lease-internal.h |    5 
 src/libsystemd-network/dhcp6-option.c         |    5 
 src/libsystemd-network/dhcp6-protocol.h       |   18 ++
 src/libsystemd-network/sd-dhcp6-client.c      |  192 ++++++++++++++++++++++----
 src/libsystemd-network/sd-dhcp6-lease.c       |   39 +++++
 src/libsystemd-network/sd-icmp6-nd.c          |   13 +
 src/libsystemd-network/test-dhcp6-client.c    |    9 +
 src/libsystemd-network/test-icmp6-rs.c        |    4 
 src/network/networkd-link.c                   |   14 +
 src/systemd/sd-dhcp6-client.h                 |    2 
 src/systemd/sd-icmp6-nd.h                     |    1 
 12 files changed, 288 insertions(+), 30 deletions(-)

New commits:
commit 37d8b536d0fb452848e2b399df0b686cfa713b31
Author: Patrik Flykt <patrik.flykt at linux.intel.com>
Date:   Tue Jun 24 16:24:50 2014 +0300

    TODO: Add items for the DHCPv6 implementation

diff --git a/TODO b/TODO
index a5f482b..8d8d694 100644
--- a/TODO
+++ b/TODO
@@ -624,6 +624,22 @@ Features:
    - export timezone information
    - FORCERENEW
 
+* dhcp6:
+   - add functions to set previously stored IPv6 addresses on startup and get
+     them at shutdown; store them in client->ia_na
+   - write more test cases
+   - implement and do duplicate address detection, see rfc 4862, 5.4.
+   - implement reconfigure support, see 5.3., 15.11. and 22.20.
+   - implement information request, see 1.2. and 18.1.5.
+   - implement support for temporary adressess (IA_TA)
+   - implement elapsed time option
+   - implement dhcpv6 authentication
+   - investigate the usefulness of Confirm messages; i.e. are there any
+     situations where the link changes without any loss in carrier detection
+     or interface down
+   - some servers don't do rapid commit without a filled in IA_NA, verify
+     this behavior
+
 External:
 
 * dbus:

commit ed6ee21953dac9c78383da00bc4514ece6b75ab5
Author: Patrik Flykt <patrik.flykt at linux.intel.com>
Date:   Wed Jun 25 16:54:30 2014 +0300

    sd-dhcp6-client: Implement Rapid Commit
    
    Add a Rapid Commit option to Solicit messages and expect a Reply to
    be received instead of an Advertise. When receiving a DHCPv6 message
    from the server in state Solicit, continue testing whether the
    message is a Reply. Ease up the message type checking, it's not fatal
    if the message is of a wrong type.
    
    Add helper functions to set/get the rapid commit of a lease. See
    RFC 3315, sections 17., 17.1.2., 17.1.4. and 18.1.8.

diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h
index 62c16c5..109e0f4 100644
--- a/src/libsystemd-network/dhcp6-lease-internal.h
+++ b/src/libsystemd-network/dhcp6-lease-internal.h
@@ -35,6 +35,7 @@ struct sd_dhcp6_lease {
         uint8_t *serverid;
         size_t serverid_len;
         uint8_t preference;
+        bool rapid_commit;
 
         DHCP6IA ia;
 
@@ -50,6 +51,9 @@ int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
 int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len);
 int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference);
 int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference);
+int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease);
+int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit);
+
 int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
 
 int dhcp6_lease_new(sd_dhcp6_lease **ret);
diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c
index f488832..e9b382c 100644
--- a/src/libsystemd-network/dhcp6-option.c
+++ b/src/libsystemd-network/dhcp6-option.c
@@ -58,13 +58,14 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
                         size_t optlen, const void *optval) {
         int r;
 
-        assert_return(optval, -EINVAL);
+        assert_return(optval || optlen == 0, -EINVAL);
 
         r = option_append_hdr(buf, buflen, code, optlen);
         if (r < 0)
                 return r;
 
-        memcpy(*buf, optval, optlen);
+        if (optval)
+                memcpy(*buf, optval, optlen);
 
         *buf += optlen;
         *buflen -= optlen;
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 60d502f..2d5bedc 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -252,6 +252,9 @@ static int client_send_message(sd_dhcp6_client *client) {
         case DHCP6_STATE_SOLICITATION:
                 message->type = DHCP6_SOLICIT;
 
+                r = dhcp6_option_append(&opt, &optlen,
+                                        DHCP6_OPTION_RAPID_COMMIT, 0, NULL);
+
                 r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
                 if (r < 0)
                         return r;
@@ -658,6 +661,13 @@ static int client_parse_message(sd_dhcp6_client *client,
                         }
 
                         break;
+
+                case DHCP6_OPTION_RAPID_COMMIT:
+                        r = dhcp6_lease_set_rapid_commit(lease);
+                        if (r < 0)
+                                return r;
+
+                        break;
                 }
         }
 
@@ -680,9 +690,10 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
 {
         int r;
         _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
+        bool rapid_commit;
 
         if (reply->type != DHCP6_REPLY)
-                return -EINVAL;
+                return 0;
 
         r = dhcp6_lease_new(&lease);
         if (r < 0)
@@ -692,6 +703,15 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
         if (r < 0)
                 return r;
 
+        if (client->state == DHCP6_STATE_SOLICITATION) {
+                r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit);
+                if (r < 0)
+                        return r;
+
+                if (!rapid_commit)
+                        return 0;
+        }
+
         dhcp6_lease_clear_timers(&client->lease->ia);
 
         client->lease = sd_dhcp6_lease_unref(client->lease);
@@ -708,7 +728,7 @@ static int client_receive_advertise(sd_dhcp6_client *client,
         uint8_t pref_advertise = 0, pref_lease = 0;
 
         if (advertise->type != DHCP6_ADVERTISE)
-                return -EINVAL;
+                return 0;
 
         r = dhcp6_lease_new(&lease);
         if (r < 0)
@@ -793,11 +813,13 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
         case DHCP6_STATE_SOLICITATION:
                 r = client_receive_advertise(client, message, len);
 
-                if (r == DHCP6_STATE_REQUEST)
+                if (r == DHCP6_STATE_REQUEST) {
                         client_start(client, r);
 
-                break;
+                        break;
+                }
 
+                /* fall through for Soliciation Rapid Commit option check */
         case DHCP6_STATE_REQUEST:
         case DHCP6_STATE_RENEW:
         case DHCP6_STATE_REBIND:
diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c
index 17a4b64..b9d0503 100644
--- a/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/libsystemd-network/sd-dhcp6-lease.c
@@ -118,6 +118,23 @@ int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) {
         return 0;
 }
 
+int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease) {
+        assert_return(lease, -EINVAL);
+
+        lease->rapid_commit = true;
+
+        return 0;
+}
+
+int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit) {
+        assert_return(lease, -EINVAL);
+        assert_return(rapid_commit, -EINVAL);
+
+        *rapid_commit = lease->rapid_commit;
+
+        return 0;
+}
+
 int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
         assert_return(lease, -EINVAL);
         assert_return(iaid, -EINVAL);

commit 3dc34fcc97b41f8b7b019027225b121dfbb9871d
Author: Patrik Flykt <patrik.flykt at linux.intel.com>
Date:   Wed Jun 25 14:06:02 2014 +0300

    sd-dhcp6-client: Implement Renew and Rebind
    
    Start sending Renew and Rebind DHCPv6 messages when respective timers T1
    and T2 expire. Rebind messages do not include a Server ID option and the
    Rebind procedure ends when the last IPv6 address valid lifetime expires,
    whereafter the client restarts the address acquisition procedure by
    Soliciting for available servers.
    
    See RFC 3315, sections 18.1.3. and 18.1.4. for details.

diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h
index 37a8671..e9ae598 100644
--- a/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/libsystemd-network/dhcp6-protocol.h
@@ -57,6 +57,10 @@ enum {
 #define DHCP6_REQ_TIMEOUT                       1 * USEC_PER_SEC
 #define DHCP6_REQ_MAX_RT                        120 * USEC_PER_SEC
 #define DHCP6_REQ_MAX_RC                        10
+#define DHCP6_REN_TIMEOUT                       10 * USEC_PER_SEC
+#define DHCP6_REN_MAX_RT                        600 * USEC_PER_SEC
+#define DHCP6_REB_TIMEOUT                       10 * USEC_PER_SEC
+#define DHCP6_REB_MAX_RT                        600 * USEC_PER_SEC
 
 enum {
         DHCP6_DUID_LLT                          = 1,
@@ -71,6 +75,8 @@ enum DHCP6State {
         DHCP6_STATE_SOLICITATION                = 2,
         DHCP6_STATE_REQUEST                     = 3,
         DHCP6_STATE_BOUND                       = 4,
+        DHCP6_STATE_RENEW                       = 5,
+        DHCP6_STATE_REBIND                      = 6,
 };
 
 enum {
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 5d65603..60d502f 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -259,7 +259,12 @@ static int client_send_message(sd_dhcp6_client *client) {
                 break;
 
         case DHCP6_STATE_REQUEST:
-                message->type = DHCP6_REQUEST;
+        case DHCP6_STATE_RENEW:
+
+                if (client->state == DHCP6_STATE_REQUEST)
+                        message->type = DHCP6_REQUEST;
+                else
+                        message->type = DHCP6_RENEW;
 
                 r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID,
                                         client->lease->serverid_len,
@@ -273,6 +278,15 @@ static int client_send_message(sd_dhcp6_client *client) {
 
                 break;
 
+        case DHCP6_STATE_REBIND:
+                message->type = DHCP6_REBIND;
+
+                r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
+                if (r < 0)
+                        return r;
+
+                break;
+
         case DHCP6_STATE_STOPPED:
         case DHCP6_STATE_RS:
         case DHCP6_STATE_BOUND:
@@ -314,6 +328,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec,
 
         log_dhcp6_client(client, "Timeout T2");
 
+        client_start(client, DHCP6_STATE_REBIND);
+
         return 0;
 }
 
@@ -330,19 +346,30 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec,
 
         log_dhcp6_client(client, "Timeout T1");
 
+        client_start(client, DHCP6_STATE_RENEW);
+
         return 0;
 }
 
 static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
                                         void *userdata) {
         sd_dhcp6_client *client = userdata;
+        DHCP6_CLIENT_DONT_DESTROY(client);
+        enum DHCP6State state;
 
         assert(s);
         assert(client);
         assert(client->event);
 
+        state = client->state;
+
         client_stop(client, DHCP6_EVENT_RESEND_EXPIRE);
 
+        /* RFC 3315, section 18.1.4., says that "...the client may choose to
+           use a Solicit message to locate a new DHCP server..." */
+        if (state == DHCP6_STATE_REBIND)
+                client_start(client, DHCP6_STATE_SOLICITATION);
+
         return 0;
 }
 
@@ -359,6 +386,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
         usec_t max_retransmit_duration;
         uint8_t max_retransmit_count = 0;
         char time_string[FORMAT_TIMESPAN_MAX];
+        uint32_t expire = 0;
 
         assert(s);
         assert(client);
@@ -389,6 +417,37 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
 
                 break;
 
+        case DHCP6_STATE_RENEW:
+                init_retransmit_time = DHCP6_REN_TIMEOUT;
+                max_retransmit_time = DHCP6_REN_MAX_RT;
+                max_retransmit_count = 0;
+
+                /* RFC 3315, section 18.1.3. says max retransmit duration will
+                   be the remaining time until T2. Instead of setting MRD,
+                   wait for T2 to trigger with the same end result */
+                max_retransmit_duration = 0;
+
+                break;
+
+        case DHCP6_STATE_REBIND:
+                init_retransmit_time = DHCP6_REB_TIMEOUT;
+                max_retransmit_time = DHCP6_REB_MAX_RT;
+                max_retransmit_count = 0;
+
+                max_retransmit_duration = 0;
+
+                if (!client->timeout_resend_expire) {
+                        r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
+                                                         &expire);
+                        if (r < 0) {
+                                client_stop(client, r);
+                                return 0;
+                        }
+                        max_retransmit_duration = expire * USEC_PER_SEC;
+                }
+
+                break;
+
         case DHCP6_STATE_STOPPED:
         case DHCP6_STATE_RS:
         case DHCP6_STATE_BOUND:
@@ -740,6 +799,9 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
                 break;
 
         case DHCP6_STATE_REQUEST:
+        case DHCP6_STATE_RENEW:
+        case DHCP6_STATE_REBIND:
+
                 r = client_receive_reply(client, message, len);
                 if (r < 0)
                         return 0;
@@ -822,6 +884,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
                 break;
 
         case DHCP6_STATE_REQUEST:
+        case DHCP6_STATE_RENEW:
+        case DHCP6_STATE_REBIND:
 
                 client->state = state;
 
@@ -883,6 +947,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
                 if (r < 0)
                         return r;
 
+                client->state = state;
+
                 return 0;
         }
 

commit 709d6710d047566c71f03e579a02c3d99fe15a3e
Author: Patrik Flykt <patrik.flykt at linux.intel.com>
Date:   Wed Jun 25 15:37:58 2014 +0300

    sd-dhcp6-lease: Add helper function to compute remaining expiry time
    
    Create a helper function to compute the remaining time in seconds from
    time T2 to the IPv6 address with the longest lifetime. The computed
    time is used as the Maximum Retransmission Duration in Rebinding state.
    See RFC 3315, section 18.1.4. for details.

diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h
index 295c223..62c16c5 100644
--- a/src/libsystemd-network/dhcp6-lease-internal.h
+++ b/src/libsystemd-network/dhcp6-lease-internal.h
@@ -42,6 +42,7 @@ struct sd_dhcp6_lease {
 };
 
 int dhcp6_lease_clear_timers(DHCP6IA *ia);
+int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
 DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia);
 
 int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c
index cbda7d8..17a4b64 100644
--- a/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/libsystemd-network/sd-dhcp6-lease.c
@@ -33,6 +33,28 @@ int dhcp6_lease_clear_timers(DHCP6IA *ia) {
         return 0;
 }
 
+int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
+        DHCP6Address *addr;
+        uint32_t valid = 0, t;
+
+        assert_return(ia, -EINVAL);
+        assert_return(expire, -EINVAL);
+
+        LIST_FOREACH(addresses, addr, ia->addresses) {
+                t = be32toh(addr->lifetime_valid);
+                if (valid < t)
+                        valid = t;
+        }
+
+        t = be32toh(ia->lifetime_t2);
+        if (t > valid)
+                return -EINVAL;
+
+        *expire = valid - t;
+
+        return 0;
+}
+
 DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
         DHCP6Address *address;
 

commit da6fe470e17fa02f3adedc779585caf8669252bd
Author: Patrik Flykt <patrik.flykt at linux.intel.com>
Date:   Tue Jun 24 16:20:32 2014 +0300

    sd-dhcp6-client: Add Option Request Option support
    
    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.

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..5d65603 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))
+                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);
 

commit 1873a3d344042e818d2a5762c0ebfc3823c8f84d
Author: Patrik Flykt <patrik.flykt at linux.intel.com>
Date:   Wed Jun 25 12:36:55 2014 +0300

    networkd: Properly stop router solicitation and DHCPv6 client
    
    When a link fails or looses carrier, always stop ongoing router
    solicitation and any DHCPv6 client that may be running.

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 44147b2..9296a59 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -236,11 +236,19 @@ static int link_stop_clients(Link *link) {
         }
 
         if (link->network->dhcp6) {
-                assert(link->dhcp6_client);
+                assert(link->icmp6_router_discovery);
+
+                if (link->dhcp6_client) {
+                        k = sd_dhcp6_client_stop(link->dhcp6_client);
+                        if (k < 0) {
+                                log_warning_link(link, "Could not stop DHCPv6 client: %s", strerror(-r));
+                                r = k;
+                        }
+                }
 
-                k = sd_dhcp6_client_stop(link->dhcp6_client);
+                k = sd_icmp6_nd_stop(link->icmp6_router_discovery);
                 if (k < 0) {
-                        log_warning_link(link, "Could not stop DHCPv6 client: %s", strerror(-r));
+                        log_warning_link(link, "Could not stop ICMPv6 router discovery: %s", strerror(-r));
                         r = k;
                 }
         }

commit 836cf0905c4a8fe3358d6b0e005192d5ee51d3e2
Author: Patrik Flykt <patrik.flykt at linux.intel.com>
Date:   Wed Jun 25 12:33:48 2014 +0300

    sd-icmp6-nd: Add function to stop ongoing ICMPv6 discovery
    
    In some use cases stopping an ongoing ICMPv6 discovery is more
    useful than always unreferencing the whole structure.

diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-icmp6-nd.c
index 10c5e5e..80915c3 100644
--- a/src/libsystemd-network/sd-icmp6-nd.c
+++ b/src/libsystemd-network/sd-icmp6-nd.c
@@ -282,6 +282,19 @@ static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec,
         return 0;
 }
 
+int sd_icmp6_nd_stop(sd_icmp6_nd *nd) {
+        assert_return(nd, -EINVAL);
+        assert_return(nd->event, -EINVAL);
+
+        log_icmp6_nd(client, "Stop ICMPv6");
+
+        icmp6_nd_init(nd);
+
+        nd->state = ICMP6_NEIGHBOR_DISCOVERY_IDLE;
+
+        return 0;
+}
+
 int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
         int r;
 
diff --git a/src/libsystemd-network/test-icmp6-rs.c b/src/libsystemd-network/test-icmp6-rs.c
index cd5c476..b81211f 100644
--- a/src/libsystemd-network/test-icmp6-rs.c
+++ b/src/libsystemd-network/test-icmp6-rs.c
@@ -127,6 +127,10 @@ static void test_rs(sd_event *e) {
                                  time_now + 2 *USEC_PER_SEC, 0,
                                  test_rs_hangcheck, NULL) >= 0);
 
+        assert(sd_icmp6_nd_stop(nd) >= 0);
+        assert(sd_icmp6_router_solicitation_start(nd) >= 0);
+        assert(sd_icmp6_nd_stop(nd) >= 0);
+
         assert(sd_icmp6_router_solicitation_start(nd) >= 0);
 
         sd_event_loop(e);
diff --git a/src/systemd/sd-icmp6-nd.h b/src/systemd/sd-icmp6-nd.h
index 5e9dc0a..73f91aa 100644
--- a/src/systemd/sd-icmp6-nd.h
+++ b/src/systemd/sd-icmp6-nd.h
@@ -51,6 +51,7 @@ sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd);
 sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd);
 int sd_icmp6_nd_new(sd_icmp6_nd **ret);
 
+int sd_icmp6_nd_stop(sd_icmp6_nd *nd);
 int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd);
 
 #endif

commit 3f0c075f8ef3344da5a6bda524540201f9204e61
Author: Patrik Flykt <patrik.flykt at linux.intel.com>
Date:   Wed Jun 25 10:36:56 2014 +0300

    sd-dhcp6-client: return NULL from _unref() like the other sd-* libraries
    
    In order to keep the refcounting working, a DONT_DESTROY macro similar
    to the one in sd-bus has been added also to DHCPv6.

diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index ab4d9e8..928f562 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -95,6 +95,12 @@ const char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
 
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref);
+#define _cleanup_dhcp6_client_unref_ _cleanup_(sd_dhcp6_client_unrefp)
+
+#define DHCP6_CLIENT_DONT_DESTROY(client) \
+        _cleanup_dhcp6_client_unref_ _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
+
 static int client_start(sd_dhcp6_client *client, enum DHCP6State state);
 
 int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
@@ -143,14 +149,9 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
         return 0;
 }
 
-static sd_dhcp6_client *client_notify(sd_dhcp6_client *client, int event) {
-        if (client->cb) {
-                client = sd_dhcp6_client_ref(client);
+static void client_notify(sd_dhcp6_client *client, int event) {
+        if (client->cb)
                 client->cb(client, event, client->userdata);
-                client = sd_dhcp6_client_unref(client);
-        }
-
-        return client;
 }
 
 static int client_reset(sd_dhcp6_client *client) {
@@ -179,14 +180,14 @@ static int client_reset(sd_dhcp6_client *client) {
         return 0;
 }
 
-static sd_dhcp6_client *client_stop(sd_dhcp6_client *client, int error) {
-        assert_return(client, NULL);
+static void client_stop(sd_dhcp6_client *client, int error) {
+        DHCP6_CLIENT_DONT_DESTROY(client);
 
-        client = client_notify(client, error);
-        if (client)
-                client_reset(client);
+        assert(client);
 
-        return client;
+        client_notify(client, error);
+
+        client_reset(client);
 }
 
 static int client_send_message(sd_dhcp6_client *client) {
@@ -633,6 +634,7 @@ static int client_receive_advertise(sd_dhcp6_client *client,
 static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
                                   void *userdata) {
         sd_dhcp6_client *client = userdata;
+        DHCP6_CLIENT_DONT_DESTROY(client);
         _cleanup_free_ DHCP6Message *message;
         int r, buflen, len;
 
@@ -704,9 +706,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
                                 return 0;
                         }
 
-                        client = client_notify(client, DHCP6_EVENT_IP_ACQUIRE);
-                        if (!client)
-                                return 0;
+                        client_notify(client, DHCP6_EVENT_IP_ACQUIRE);
                 }
 
                 break;
@@ -935,12 +935,9 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
         return client;
 }
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref);
-#define _cleanup_dhcp6_client_free_ _cleanup_(sd_dhcp6_client_unrefp)
-
 int sd_dhcp6_client_new(sd_dhcp6_client **ret)
 {
-        _cleanup_dhcp6_client_free_ sd_dhcp6_client *client = NULL;
+        _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL;
         sd_id128_t machine_id;
         int r;
 



More information about the systemd-commits mailing list