From ed6ee21953dac9c78383da00bc4514ece6b75ab5 Mon Sep 17 00:00:00 2001 From: Patrik Flykt Date: Wed, 25 Jun 2014 16:54:30 +0300 Subject: [PATCH] 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. --- src/libsystemd-network/dhcp6-lease-internal.h | 4 +++ src/libsystemd-network/dhcp6-option.c | 5 ++-- src/libsystemd-network/sd-dhcp6-client.c | 30 ++++++++++++++++--- src/libsystemd-network/sd-dhcp6-lease.c | 17 +++++++++++ 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h index 62c16c5b6..109e0f4f2 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 f488832cf..e9b382c17 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 60d502fcb..2d5bedcb8 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 17a4b6406..b9d050364 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); -- 2.30.2