Receive and parse a Reply from the server. Set up T1 and T2 timers and notify the library user of an acquired DHCPv6 lease. --- src/libsystemd-network/dhcp6-protocol.h | 1 + src/libsystemd-network/sd-dhcp6-client.c | 145 +++++++++++++++++++++++++++++++ src/systemd/sd-dhcp6-client.h | 1 + 3 files changed, 147 insertions(+)
diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index a3a8be1..95d37f7 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -70,6 +70,7 @@ enum DHCP6State { DHCP6_STATE_RS = 1, DHCP6_STATE_SOLICITATION = 2, DHCP6_STATE_REQUEST = 3, + DHCP6_STATE_BOUND = 4, }; enum { diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 312c84c..15e5ea0 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -239,6 +239,7 @@ static int client_send_message(sd_dhcp6_client *client) { case DHCP6_STATE_STOPPED: case DHCP6_STATE_RS: + case DHCP6_STATE_BOUND: return -EINVAL; } @@ -258,6 +259,38 @@ static int client_send_message(sd_dhcp6_client *client) { return 0; } +static int client_timeout_t2(sd_event_source *s, uint64_t usec, + void *userdata) { + sd_dhcp6_client *client = userdata; + + assert_return(s, -EINVAL); + assert_return(client, -EINVAL); + assert_return(client->lease, -EINVAL); + + client->lease->ia.timeout_t2 = + sd_event_source_unref(client->lease->ia.timeout_t2); + + log_dhcp6_client(client, "Timeout T2"); + + return 0; +} + +static int client_timeout_t1(sd_event_source *s, uint64_t usec, + void *userdata) { + sd_dhcp6_client *client = userdata; + + assert_return(s, -EINVAL); + assert_return(client, -EINVAL); + assert_return(client->lease, -EINVAL); + + client->lease->ia.timeout_t1 = + sd_event_source_unref(client->lease->ia.timeout_t1); + + log_dhcp6_client(client, "Timeout T1"); + + return 0; +} + static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp6_client *client = userdata; @@ -316,6 +349,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, case DHCP6_STATE_STOPPED: case DHCP6_STATE_RS: + case DHCP6_STATE_BOUND: return 0; } @@ -541,6 +575,32 @@ static int client_parse_message(sd_dhcp6_client *client, return r; } +static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, + size_t len) +{ + int r; + _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; + + if (reply->type != DHCP6_REPLY) + return -EINVAL; + + r = dhcp6_lease_new(&lease); + if (r < 0) + return -ENOMEM; + + r = client_parse_message(client, reply, len, lease); + if (r < 0) + return r; + + dhcp6_lease_clear_timers(&client->lease->ia); + + client->lease = sd_dhcp6_lease_unref(client->lease); + client->lease = lease; + lease = NULL; + + return DHCP6_STATE_BOUND; +} + static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) { int r; @@ -639,6 +699,29 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, break; case DHCP6_STATE_REQUEST: + r = client_receive_reply(client, message, len); + if (r < 0) + return 0; + + if (r == DHCP6_STATE_BOUND) { + + r = client_start(client, DHCP6_STATE_BOUND); + if (r < 0) { + client_stop(client, r); + return 0; + } + + client = client_notify(client, DHCP6_EVENT_IP_ACQUIRE); + if (!client) + return 0; + } + + break; + + case DHCP6_STATE_BOUND: + + break; + case DHCP6_STATE_STOPPED: case DHCP6_STATE_RS: return 0; @@ -655,6 +738,8 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { int r; + usec_t timeout, time_now; + char time_string[FORMAT_TIMESPAN_MAX]; assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); @@ -698,9 +783,69 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) break; case DHCP6_STATE_REQUEST: + client->state = state; break; + + case DHCP6_STATE_BOUND: + + r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now); + if (r < 0) + return r; + + if (client->lease->ia.lifetime_t1 == 0xffffffff || + client->lease->ia.lifetime_t2 == 0xffffffff) { + + log_dhcp6_client(client, "infinite T1 0x%08x or T2 " + "0x%08x", + be32toh(client->lease->ia.lifetime_t1), + be32toh(client->lease->ia.lifetime_t2)); + + return 0; + } + + timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC); + + log_dhcp6_client(client, "T1 expires in %s", + format_timespan(time_string, + FORMAT_TIMESPAN_MAX, + timeout, 0)); + + r = sd_event_add_time(client->event, + &client->lease->ia.timeout_t1, + CLOCK_MONOTONIC, time_now + timeout, + 10 * USEC_PER_SEC, client_timeout_t1, + client); + if (r < 0) + return r; + + r = sd_event_source_set_priority(client->lease->ia.timeout_t1, + client->event_priority); + if (r < 0) + return r; + + timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC); + + log_dhcp6_client(client, "T2 expires in %s", + format_timespan(time_string, + FORMAT_TIMESPAN_MAX, + timeout, 0)); + + r = sd_event_add_time(client->event, + &client->lease->ia.timeout_t2, + CLOCK_MONOTONIC, time_now + timeout, + 10 * USEC_PER_SEC, client_timeout_t2, + client); + if (r < 0) + return r; + + r = sd_event_source_set_priority(client->lease->ia.timeout_t2, + client->event_priority); + if (r < 0) + return r; + + return 0; } client->transaction_id = random_u32() & htobe32(0x00ffffff); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index aadb622..81e26fe 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -33,6 +33,7 @@ enum { DHCP6_EVENT_NO_STATEFUL_CONFIGURATION = 10, DHCP6_EVENT_RESEND_EXPIRE = 11, DHCP6_EVENT_RETRANS_MAX = 12, + DHCP6_EVENT_IP_ACQUIRE = 13, }; typedef struct sd_dhcp6_client sd_dhcp6_client; -- 1.9.1 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel