X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-network%2Fsd-dhcp6-client.c;h=c6c82eb349161ec4d856b0648c968045e73a343d;hb=8f077bf94e129fa1b6f0159e3140c4326f1066cf;hp=5d65603dc229dc3331ab887695c03d0e8be89b0b;hpb=da6fe470e17fa02f3adedc779585caf8669252bd;p=elogind.git diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 5d65603dc..c6c82eb34 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -252,6 +252,11 @@ 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); + if (r < 0) + return r; + r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na); if (r < 0) return r; @@ -259,7 +264,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,8 +283,16 @@ 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: return -EINVAL; } @@ -314,6 +332,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 +350,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; } @@ -355,10 +386,11 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) { int r = 0; sd_dhcp6_client *client = userdata; - usec_t time_now, init_retransmit_time, max_retransmit_time; - usec_t max_retransmit_duration; + usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0; + usec_t max_retransmit_duration = 0; uint8_t max_retransmit_count = 0; char time_string[FORMAT_TIMESPAN_MAX]; + uint32_t expire = 0; assert(s); assert(client); @@ -376,8 +408,6 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, init_retransmit_time = DHCP6_SOL_TIMEOUT; max_retransmit_time = DHCP6_SOL_MAX_RT; - max_retransmit_count = 0; - max_retransmit_duration = 0; break; @@ -385,12 +415,36 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, init_retransmit_time = DHCP6_REQ_TIMEOUT; max_retransmit_time = DHCP6_REQ_MAX_RT; max_retransmit_count = DHCP6_REQ_MAX_RC; - max_retransmit_duration = 0; + + break; + + case DHCP6_STATE_RENEW: + init_retransmit_time = DHCP6_REN_TIMEOUT; + max_retransmit_time = DHCP6_REN_MAX_RT; + + /* 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 */ + + break; + + case DHCP6_STATE_REBIND: + init_retransmit_time = DHCP6_REB_TIMEOUT; + max_retransmit_time = DHCP6_REB_MAX_RT; + + 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: return 0; } @@ -406,7 +460,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, client->retransmit_count++; - r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now); + r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); if (r < 0) goto error; @@ -430,7 +484,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, client->retransmit_time, 0)); r = sd_event_add_time(client->event, &client->timeout_resend, - CLOCK_MONOTONIC, + clock_boottime_or_monotonic(), time_now + client->retransmit_time, 10 * USEC_PER_MSEC, client_timeout_resend, client); @@ -449,7 +503,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, r = sd_event_add_time(client->event, &client->timeout_resend_expire, - CLOCK_MONOTONIC, + clock_boottime_or_monotonic(), time_now + max_retransmit_duration, USEC_PER_SEC, client_timeout_resend_expire, client); @@ -470,6 +524,9 @@ error: } static int client_ensure_iaid(sd_dhcp6_client *client) { + /* name is a pointer to memory in the udev_device struct, so must + have the same scope */ + _cleanup_udev_device_unref_ struct udev_device *device = NULL; const char *name = NULL; uint64_t id; @@ -481,7 +538,6 @@ static int client_ensure_iaid(sd_dhcp6_client *client) { if (detect_container(NULL) <= 0) { /* not in a container, udev will be around */ _cleanup_udev_unref_ struct udev *udev; - _cleanup_udev_device_unref_ struct udev_device *device = NULL; char ifindex_str[2 + DECIMAL_STR_MAX(int)]; udev = udev_new(); @@ -599,6 +655,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; } } @@ -621,9 +684,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) @@ -633,7 +697,17 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, if (r < 0) return r; - dhcp6_lease_clear_timers(&client->lease->ia); + 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; + } + + if (client->lease) + dhcp6_lease_clear_timers(&client->lease->ia); client->lease = sd_dhcp6_lease_unref(client->lease); client->lease = lease; @@ -649,7 +723,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) @@ -734,12 +808,17 @@ 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: + r = client_receive_reply(client, message, len); if (r < 0) return 0; @@ -762,7 +841,6 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, break; case DHCP6_STATE_STOPPED: - case DHCP6_STATE_RS: return 0; } @@ -793,7 +871,6 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) switch (state) { case DHCP6_STATE_STOPPED: - case DHCP6_STATE_RS: case DHCP6_STATE_SOLICITATION: r = client_ensure_iaid(client); @@ -822,6 +899,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; @@ -829,7 +908,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) case DHCP6_STATE_BOUND: - r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now); + r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); if (r < 0) return r; @@ -852,7 +931,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) r = sd_event_add_time(client->event, &client->lease->ia.timeout_t1, - CLOCK_MONOTONIC, time_now + timeout, + clock_boottime_or_monotonic(), time_now + timeout, 10 * USEC_PER_SEC, client_timeout_t1, client); if (r < 0) @@ -872,7 +951,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) r = sd_event_add_time(client->event, &client->lease->ia.timeout_t2, - CLOCK_MONOTONIC, time_now + timeout, + clock_boottime_or_monotonic(), time_now + timeout, 10 * USEC_PER_SEC, client_timeout_t2, client); if (r < 0) @@ -883,13 +962,15 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) if (r < 0) return r; + client->state = state; + return 0; } client->transaction_id = random_u32() & htobe32(0x00ffffff); r = sd_event_add_time(client->event, &client->timeout_resend, - CLOCK_MONOTONIC, 0, 0, client_timeout_resend, + clock_boottime_or_monotonic(), 0, 0, client_timeout_resend, client); if (r < 0) return r;