summaryrefslogtreecommitdiff
path: root/src/libsystemd-dhcp
diff options
context:
space:
mode:
authorPatrik Flykt <patrik.flykt@linux.intel.com>2013-12-09 23:43:30 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2013-12-12 11:43:34 -0500
commit51debc1e396a14d7c1204d8661c4eb1056c47670 (patch)
treefa33f392a2291c63e2ddb36b6dec31ac21fc3482 /src/libsystemd-dhcp
parent3e3d8f7857a7a59d62cc5bd1e4e792dc4d0f40b3 (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.c116
-rw-r--r--src/libsystemd-dhcp/dhcp-protocol.h2
2 files changed, 117 insertions, 1 deletions
diff --git a/src/libsystemd-dhcp/dhcp-client.c b/src/libsystemd-dhcp/dhcp-client.c
index a15866932..d03435b92 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 f5f490d8b..1e59965dc 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,
};