Compute the default T1 and T2 timer values if they were not set by the DHCP server. Verify that the values are reasonable. --- src/dhcp/client.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/dhcp/protocol.h | 2 + 2 files changed, 124 insertions(+), 1 deletion(-)
diff --git a/src/dhcp/client.c b/src/dhcp/client.c index 669804a..50008a9 100644 --- a/src/dhcp/client.c +++ b/src/dhcp/client.c @@ -34,6 +34,8 @@ struct DHCPLease { uint32_t lifetime; + uint32_t t2; + uint32_t t1; struct in_addr address; struct in_addr server_address; struct in_addr subnet_mask; @@ -57,6 +59,10 @@ struct DHCPClient { uint32_t xid; uint64_t start_time; unsigned int attempt; + uint64_t request_sent; + sd_event_source *timeout_expire; + sd_event_source *timeout_t1; + sd_event_source *timeout_t2; DHCPLease *lease; }; @@ -177,6 +183,16 @@ static int client_stop(DHCPClient *client, int error) client->timeout_resend = sd_event_source_unref(client->timeout_resend); + if (client->timeout_expire) + client->timeout_expire = + sd_event_source_unref(client->timeout_expire); + if (client->timeout_t2) + client->timeout_t2 = + sd_event_source_unref(client->timeout_t2); + if (client->timeout_t1) + client->timeout_t1 = + sd_event_source_unref(client->timeout_t1); + client->attempt = 1; switch (client->state) { @@ -184,6 +200,7 @@ static int client_stop(DHCPClient *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; @@ -191,7 +208,6 @@ static int client_stop(DHCPClient *client, int error) case DHCP_STATE_INIT_REBOOT: case DHCP_STATE_REBOOTING: - case DHCP_STATE_BOUND: case DHCP_STATE_RENEWING: case DHCP_STATE_REBINDING: @@ -447,6 +463,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: @@ -466,6 +484,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, uint8_t *option, void *user_data) { @@ -499,6 +533,22 @@ static int client_parse_offer(uint8_t code, uint8_t len, uint8_t *option, memcpy(&lease->router.s_addr, option, 4); break; + + case DHCP_OPTION_RENEWAL_T1_TIME: + if (len == 4) { + memcpy(&val, option, 4); + lease->t1 = ntohl(val); + } + + break; + + case DHCP_OPTION_REBINDING_T2_TIME: + if (len == 4) { + memcpy(&val, option, 4); + lease->t2 = ntohl(val); + } + + break; } return 0; @@ -635,6 +685,72 @@ error: return err; } +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(DHCPClient *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) { @@ -697,6 +813,11 @@ static int client_receive_raw_message(sd_event_source *s, int fd, client->last_addr->s_addr = client->lease->address.s_addr; + err = client_set_lease_timeouts(client, + now(CLOCK_MONOTONIC)); + if (err < 0 ) + goto error; + client_notify(client, DHCP_EVENT_IP_ACQUIRE); close(client->fd); diff --git a/src/dhcp/protocol.h b/src/dhcp/protocol.h index 6503931..773c29c 100644 --- a/src/dhcp/protocol.h +++ b/src/dhcp/protocol.h @@ -100,5 +100,7 @@ typedef enum DHCPState DHCPState; #define DHCP_OPTION_SERVER_IDENTIFIER 54 #define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 #define DHCP_OPTION_MAXIMUM_MESSAGE_SIZE 57 +#define DHCP_OPTION_RENEWAL_T1_TIME 58 +#define DHCP_OPTION_REBINDING_T2_TIME 59 #define DHCP_OPTION_CLIENT_IDENTIFIER 61 #define DHCP_OPTION_END 255 -- 1.7.10.4 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel