From 95e15c09350acf58d4707056ae2614570883ef66 Mon Sep 17 00:00:00 2001 From: Grant Erickson Date: Tue, 28 Feb 2012 08:30:00 -0800 Subject: [PATCH] gdhcp: set secs in a RFC 951- and 2131-compliant manner This patch sets the BOOTP secs field in a RFC 951- and 2131-compliant manner for DHCPv4 DISCOVER and REQUEST/SELECT packets. Certain DHCP servers, such as that implemented in Mac OS X (< 10.7) for its "Internet Sharing" feature, refuse to issue a DHCP lease to clients that have not set a non-zero value in their DISCOVER or REQUEST packets. In fact, based on http://hints.macworld.com/article.php? story=20071223001432304, it's not non-zero but a value greater than four (4) seconds to allow another "authoritative" DHCP server on the subnet to reply first. Side-by-side packet analysis of Mac OS X, iOS, Android, ISC and Windows clients show that these clients set the BOOTP 'secs' field and are successfully issued a DHCP lease by Mac OS X. By contrast, a connman-based client will issue 10 back-to-back DISCOVER packets and will not be returned a DHCP OFFER from the server. --- gdhcp/client.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/gdhcp/client.c b/gdhcp/client.c index a3b4b8a..cf4cc3c 100644 --- a/gdhcp/client.c +++ b/gdhcp/client.c @@ -88,6 +88,7 @@ struct _GDHCPClient { uint32_t server_ip; uint32_t requested_ip; char *assigned_ip; + time_t start; uint32_t lease_seconds; ListenMode listen_mode; int listener_sockfd; @@ -339,6 +340,17 @@ static void add_send_options(GDHCPClient *dhcp_client, add_binary_option, packet); } +/* + * Return an RFC 951- and 2131-complaint BOOTP 'secs' value that + * represents the number of seconds elapsed from the start of + * attempting DHCP to satisfy some DHCP servers that allow for an + * "authoritative" reply before responding. + */ +static uint16_t dhcp_attempt_secs(GDHCPClient *dhcp_client) +{ + return htons(MIN(time(NULL) - dhcp_client->start, UINT16_MAX)); +} + static int send_discover(GDHCPClient *dhcp_client, uint32_t requested) { struct dhcp_packet packet; @@ -348,6 +360,7 @@ static int send_discover(GDHCPClient *dhcp_client, uint32_t requested) init_packet(dhcp_client, &packet, DHCPDISCOVER); packet.xid = dhcp_client->xid; + packet.secs = dhcp_attempt_secs(dhcp_client); if (requested) dhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); @@ -374,6 +387,7 @@ static int send_select(GDHCPClient *dhcp_client) init_packet(dhcp_client, &packet, DHCPREQUEST); packet.xid = dhcp_client->xid; + packet.secs = dhcp_attempt_secs(dhcp_client); dhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, dhcp_client->requested_ip); @@ -2240,6 +2254,7 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address) return re; dhcp_client->xid = rand(); + dhcp_client->start = time(NULL); } if (last_address == NULL) { -- 2.7.4