diff options
author | Patrik Flykt <patrik.flykt@linux.intel.com> | 2013-12-09 23:43:30 +0200 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2013-12-12 11:43:34 -0500 |
commit | 51debc1e396a14d7c1204d8661c4eb1056c47670 (patch) | |
tree | fa33f392a2291c63e2ddb36b6dec31ac21fc3482 /src/libsystemd-dhcp | |
parent | 3e3d8f7857a7a59d62cc5bd1e4e792dc4d0f40b3 (diff) |
dhcp: Compute expire, T1 and T2 timers
Compute the default T1 and T2 timer values if they were not set by
the DHCP server. Verify that the values are reasonable.
Diffstat (limited to 'src/libsystemd-dhcp')
-rw-r--r-- | src/libsystemd-dhcp/dhcp-client.c | 116 | ||||
-rw-r--r-- | src/libsystemd-dhcp/dhcp-protocol.h | 2 |
2 files changed, 117 insertions, 1 deletions
diff --git a/src/libsystemd-dhcp/dhcp-client.c b/src/libsystemd-dhcp/dhcp-client.c index a15866932c..d03435b929 100644 --- a/src/libsystemd-dhcp/dhcp-client.c +++ b/src/libsystemd-dhcp/dhcp-client.c @@ -33,6 +33,8 @@ #define DHCP_CLIENT_MIN_OPTIONS_SIZE 312 struct DHCPLease { + uint32_t t1; + uint32_t t2; uint32_t lifetime; uint32_t address; uint32_t server_address; @@ -57,6 +59,10 @@ struct sd_dhcp_client { uint32_t xid; usec_t start_time; unsigned int attempt; + usec_t request_sent; + sd_event_source *timeout_t1; + sd_event_source *timeout_t2; + sd_event_source *timeout_expire; DHCPLease *lease; }; @@ -157,6 +163,10 @@ static int client_stop(sd_dhcp_client *client, int error) client->timeout_resend = sd_event_source_unref(client->timeout_resend); + client->timeout_t1 = sd_event_source_unref(client->timeout_t1); + client->timeout_t2 = sd_event_source_unref(client->timeout_t2); + client->timeout_expire = sd_event_source_unref(client->timeout_expire); + client->attempt = 1; switch (client->state) { @@ -164,6 +174,7 @@ static int client_stop(sd_dhcp_client *client, int error) case DHCP_STATE_INIT: case DHCP_STATE_SELECTING: case DHCP_STATE_REQUESTING: + case DHCP_STATE_BOUND: client->start_time = 0; client->state = DHCP_STATE_INIT; @@ -171,7 +182,6 @@ static int client_stop(sd_dhcp_client *client, int error) case DHCP_STATE_INIT_REBOOT: case DHCP_STATE_REBOOTING: - case DHCP_STATE_BOUND: case DHCP_STATE_RENEWING: case DHCP_STATE_REBINDING: @@ -427,6 +437,8 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, if (err < 0 && client->attempt >= 64) goto error; + client->request_sent = usec; + break; case DHCP_STATE_INIT_REBOOT: @@ -448,6 +460,22 @@ error: return 0; } +static int client_timeout_expire(sd_event_source *s, uint64_t usec, + void *userdata) +{ + return 0; +} + +static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) +{ + return 0; +} + +static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) +{ + return 0; +} + static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option, void *user_data) { @@ -481,6 +509,22 @@ static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option, memcpy(&lease->router, option, 4); break; + + case DHCP_OPTION_RENEWAL_T1_TIME: + if (len == 4) { + memcpy(&val, option, 4); + lease->t1 = be32toh(val); + } + + break; + + case DHCP_OPTION_REBINDING_T2_TIME: + if (len == 4) { + memcpy(&val, option, 4); + lease->t2 = be32toh(val); + } + + break; } return 0; @@ -610,6 +654,72 @@ error: return r; } +static uint64_t client_compute_timeout(uint64_t request_sent, + uint32_t lifetime) +{ + return request_sent + (lifetime - 3) * USEC_PER_SEC + + + (random_u() & 0x1fffff); +} + +static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec) +{ + int err; + uint64_t next_timeout; + + if (client->lease->lifetime < 10) + return -EINVAL; + + if (!client->lease->t1) + client->lease->t1 = client->lease->lifetime / 2; + + next_timeout = client_compute_timeout(client->request_sent, + client->lease->t1); + if (next_timeout < usec) + return -EINVAL; + + err = sd_event_add_monotonic(client->event, next_timeout, + 10 * USEC_PER_MSEC, + client_timeout_t1, client, + &client->timeout_t1); + if (err < 0) + return err; + + if (!client->lease->t2) + client->lease->t2 = client->lease->lifetime * 7 / 8; + + if (client->lease->t2 < client->lease->t1) + return -EINVAL; + + if (client->lease->lifetime < client->lease->t2) + return -EINVAL; + + next_timeout = client_compute_timeout(client->request_sent, + client->lease->t2); + if (next_timeout < usec) + return -EINVAL; + + err = sd_event_add_monotonic(client->event, next_timeout, + 10 * USEC_PER_MSEC, + client_timeout_t2, client, + &client->timeout_t2); + if (err < 0) + return err; + + next_timeout = client_compute_timeout(client->request_sent, + client->lease->lifetime); + if (next_timeout < usec) + return -EINVAL; + + err = sd_event_add_monotonic(client->event, next_timeout, + 10 * USEC_PER_MSEC, + client_timeout_expire, client, + &client->timeout_expire); + if (err < 0) + return err; + + return 0; +} + static int client_receive_raw_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) { @@ -666,6 +776,10 @@ static int client_receive_raw_message(sd_event_source *s, int fd, client->last_addr = client->lease->address; + r = client_set_lease_timeouts(client, time_now); + if (r < 0 ) + goto error; + client_notify(client, DHCP_EVENT_IP_ACQUIRE); close(client->fd); diff --git a/src/libsystemd-dhcp/dhcp-protocol.h b/src/libsystemd-dhcp/dhcp-protocol.h index f5f490d8b9..1e59965dc0 100644 --- a/src/libsystemd-dhcp/dhcp-protocol.h +++ b/src/libsystemd-dhcp/dhcp-protocol.h @@ -112,6 +112,8 @@ enum { DHCP_OPTION_SERVER_IDENTIFIER = 54, DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, + DHCP_OPTION_RENEWAL_T1_TIME = 58, + DHCP_OPTION_REBINDING_T2_TIME = 59, DHCP_OPTION_CLIENT_IDENTIFIER = 61, DHCP_OPTION_END = 255, }; |