|
|
9ecd5b8 |
From 72dec8120893e76d51e430b4ee5a263e885d0974 Mon Sep 17 00:00:00 2001
|
|
|
9ecd5b8 |
From: Dan Williams <dcbw@redhat.com>
|
|
|
9ecd5b8 |
Date: Tue, 4 Nov 2014 11:20:43 -0600
|
|
|
9ecd5b8 |
Subject: [PATCH] sd-dhcp-client: fix REBOOT state handling
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
client->secs wasn't getting set in the REBOOT state, causing
|
|
|
9ecd5b8 |
an assertion. REBOOT should work the same way as INIT, per
|
|
|
9ecd5b8 |
RFC 2131:
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
secs 2 Filled in by client, seconds elapsed since client
|
|
|
9ecd5b8 |
began address acquisition or renewal process.
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
REBOOT is necessary because some DHCP servers (eg on
|
|
|
9ecd5b8 |
home routers) do not hand back the same IP address unless the
|
|
|
9ecd5b8 |
'ciaddr' field is filled with that address, which DISCOVER
|
|
|
9ecd5b8 |
cannot do per the RFCs. This leads to multiple leases
|
|
|
9ecd5b8 |
on machine reboot or DHCP client restart.
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
(cherry picked from commit d8d74ef06fa0ccf39084a6177e70e4c2297cca57)
|
|
|
9ecd5b8 |
---
|
|
|
9ecd5b8 |
src/libsystemd-network/sd-dhcp-client.c | 31 +++++++++++++------------------
|
|
|
9ecd5b8 |
1 file changed, 13 insertions(+), 18 deletions(-)
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
|
|
|
9ecd5b8 |
index 1f7f238ca0..9986b5257b 100644
|
|
|
9ecd5b8 |
--- a/src/libsystemd-network/sd-dhcp-client.c
|
|
|
9ecd5b8 |
+++ b/src/libsystemd-network/sd-dhcp-client.c
|
|
|
9ecd5b8 |
@@ -68,7 +68,6 @@ struct sd_dhcp_client {
|
|
|
9ecd5b8 |
uint32_t mtu;
|
|
|
9ecd5b8 |
uint32_t xid;
|
|
|
9ecd5b8 |
usec_t start_time;
|
|
|
9ecd5b8 |
- uint16_t secs;
|
|
|
9ecd5b8 |
unsigned int attempt;
|
|
|
9ecd5b8 |
usec_t request_sent;
|
|
|
9ecd5b8 |
sd_event_source *timeout_t1;
|
|
|
9ecd5b8 |
@@ -321,10 +320,12 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
|
|
|
9ecd5b8 |
_cleanup_free_ DHCPPacket *packet;
|
|
|
9ecd5b8 |
size_t optlen, optoffset, size;
|
|
|
9ecd5b8 |
be16_t max_size;
|
|
|
9ecd5b8 |
+ usec_t time_now;
|
|
|
9ecd5b8 |
+ uint16_t secs;
|
|
|
9ecd5b8 |
int r;
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
assert(client);
|
|
|
9ecd5b8 |
- assert(client->secs);
|
|
|
9ecd5b8 |
+ assert(client->start_time);
|
|
|
9ecd5b8 |
assert(ret);
|
|
|
9ecd5b8 |
assert(_optlen);
|
|
|
9ecd5b8 |
assert(_optoffset);
|
|
|
9ecd5b8 |
@@ -344,7 +345,15 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
/* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
|
|
|
9ecd5b8 |
refuse to issue an DHCP lease if 'secs' is set to zero */
|
|
|
9ecd5b8 |
- packet->dhcp.secs = htobe16(client->secs);
|
|
|
9ecd5b8 |
+ r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
|
|
|
9ecd5b8 |
+ if (r < 0)
|
|
|
9ecd5b8 |
+ return r;
|
|
|
9ecd5b8 |
+ assert(time_now >= client->start_time);
|
|
|
9ecd5b8 |
+
|
|
|
9ecd5b8 |
+ /* seconds between sending first and last DISCOVER
|
|
|
9ecd5b8 |
+ * must always be strictly positive to deal with broken servers */
|
|
|
9ecd5b8 |
+ secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
|
|
|
9ecd5b8 |
+ packet->dhcp.secs = htobe16(secs);
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
/* RFC2132 section 4.1
|
|
|
9ecd5b8 |
A client that cannot receive unicast IP datagrams until its protocol
|
|
|
9ecd5b8 |
@@ -441,24 +450,12 @@ static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
|
|
|
9ecd5b8 |
static int client_send_discover(sd_dhcp_client *client) {
|
|
|
9ecd5b8 |
_cleanup_free_ DHCPPacket *discover = NULL;
|
|
|
9ecd5b8 |
size_t optoffset, optlen;
|
|
|
9ecd5b8 |
- usec_t time_now;
|
|
|
9ecd5b8 |
int r;
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
assert(client);
|
|
|
9ecd5b8 |
assert(client->state == DHCP_STATE_INIT ||
|
|
|
9ecd5b8 |
client->state == DHCP_STATE_SELECTING);
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
- /* See RFC2131 section 4.4.1 */
|
|
|
9ecd5b8 |
-
|
|
|
9ecd5b8 |
- r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
|
|
|
9ecd5b8 |
- if (r < 0)
|
|
|
9ecd5b8 |
- return r;
|
|
|
9ecd5b8 |
- assert(time_now >= client->start_time);
|
|
|
9ecd5b8 |
-
|
|
|
9ecd5b8 |
- /* seconds between sending first and last DISCOVER
|
|
|
9ecd5b8 |
- * must always be strictly positive to deal with broken servers */
|
|
|
9ecd5b8 |
- client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
|
|
|
9ecd5b8 |
-
|
|
|
9ecd5b8 |
r = client_message_init(client, &discover, DHCP_DISCOVER,
|
|
|
9ecd5b8 |
&optlen, &optoffset);
|
|
|
9ecd5b8 |
if (r < 0)
|
|
|
9ecd5b8 |
@@ -875,10 +872,8 @@ static int client_start(sd_dhcp_client *client) {
|
|
|
9ecd5b8 |
}
|
|
|
9ecd5b8 |
client->fd = r;
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
- if (client->state == DHCP_STATE_INIT) {
|
|
|
9ecd5b8 |
+ if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT)
|
|
|
9ecd5b8 |
client->start_time = now(clock_boottime_or_monotonic());
|
|
|
9ecd5b8 |
- client->secs = 0;
|
|
|
9ecd5b8 |
- }
|
|
|
9ecd5b8 |
|
|
|
9ecd5b8 |
return client_initialize_events(client, client_receive_message_raw);
|
|
|
9ecd5b8 |
}
|