[systemd-devel] [PATCH] sd-dhcp-client: fix REBOOT state handling
Dan Williams
dcbw at redhat.com
Tue Nov 18 09:20:15 PST 2014
On Tue, 2014-11-04 at 11:20 -0600, Dan Williams wrote:
> client->secs wasn't getting set in the REBOOT state, causing
> an assertion. REBOOT should work the same way as INIT, per
> RFC 2131:
>
> secs 2 Filled in by client, seconds elapsed since client
> began address acquisition or renewal process.
>
> REBOOT is necessary because some DHCP servers (eg on
> home routers) do not hand back the same IP address unless the
> 'ciaddr' field is filled with that address, which DISCOVER
> cannot do per the RFCs. This leads to multiple leases
> on machine reboot or DHCP client restart.
Anyone had a chance to review this patch?
> ---
> src/libsystemd-network/sd-dhcp-client.c | 31 +++++++++++++------------------
> 1 file changed, 13 insertions(+), 18 deletions(-)
>
> diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
> index a8ec654..300fc38 100644
> --- a/src/libsystemd-network/sd-dhcp-client.c
> +++ b/src/libsystemd-network/sd-dhcp-client.c
> @@ -89,7 +89,6 @@ struct sd_dhcp_client {
> uint32_t mtu;
> uint32_t xid;
> usec_t start_time;
> - uint16_t secs;
> unsigned int attempt;
> usec_t request_sent;
> sd_event_source *timeout_t1;
> @@ -399,10 +398,12 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
> _cleanup_free_ DHCPPacket *packet;
> size_t optlen, optoffset, size;
> be16_t max_size;
> + usec_t time_now;
> + uint16_t secs;
> int r;
>
> assert(client);
> - assert(client->secs);
> + assert(client->start_time);
> assert(ret);
> assert(_optlen);
> assert(_optoffset);
> @@ -422,7 +423,15 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
>
> /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
> refuse to issue an DHCP lease if 'secs' is set to zero */
> - packet->dhcp.secs = htobe16(client->secs);
> + r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
> + if (r < 0)
> + return r;
> + assert(time_now >= client->start_time);
> +
> + /* seconds between sending first and last DISCOVER
> + * must always be strictly positive to deal with broken servers */
> + secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
> + packet->dhcp.secs = htobe16(secs);
>
> /* RFC2132 section 4.1
> A client that cannot receive unicast IP datagrams until its protocol
> @@ -529,24 +538,12 @@ static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
> static int client_send_discover(sd_dhcp_client *client) {
> _cleanup_free_ DHCPPacket *discover = NULL;
> size_t optoffset, optlen;
> - usec_t time_now;
> int r;
>
> assert(client);
> assert(client->state == DHCP_STATE_INIT ||
> client->state == DHCP_STATE_SELECTING);
>
> - /* See RFC2131 section 4.4.1 */
> -
> - r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
> - if (r < 0)
> - return r;
> - assert(time_now >= client->start_time);
> -
> - /* seconds between sending first and last DISCOVER
> - * must always be strictly positive to deal with broken servers */
> - client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
> -
> r = client_message_init(client, &discover, DHCP_DISCOVER,
> &optlen, &optoffset);
> if (r < 0)
> @@ -963,10 +960,8 @@ static int client_start(sd_dhcp_client *client) {
> }
> client->fd = r;
>
> - if (client->state == DHCP_STATE_INIT) {
> + if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT)
> client->start_time = now(clock_boottime_or_monotonic());
> - client->secs = 0;
> - }
>
> return client_initialize_events(client, client_receive_message_raw);
> }
More information about the systemd-devel
mailing list