X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-network%2Fsd-dhcp6-client.c;h=4f60578bc3184707767c2bbec0e7b11d6d2fdb31;hp=5d65603dc229dc3331ab887695c03d0e8be89b0b;hb=4b4923e65423e60d755841b5b264730e8f3deab3;hpb=da6fe470e17fa02f3adedc779585caf8669252bd diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 5d65603dc..4f60578bc 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,6 +283,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 +333,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 +351,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 +387,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 +409,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,7 +416,32 @@ 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; @@ -470,6 +526,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 +540,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 +657,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 +686,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 +699,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 +725,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 +810,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; @@ -822,6 +903,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 +966,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) if (r < 0) return r; + client->state = state; + return 0; }