summaryrefslogtreecommitdiff
path: root/gdhcp/client.c
diff options
context:
space:
mode:
authorZhang zhengguang <zhengguang.zhang@intel.com>2014-10-29 11:03:47 +0800
committerZhang zhengguang <zhengguang.zhang@intel.com>2014-10-29 11:03:47 +0800
commitbcae74da8fa2958b3fec9153fc33e41f0e0317bf (patch)
tree06a00f6457307467fee4f6580dce4a1a857751c1 /gdhcp/client.c
parent1b9d0a62f59bb48c8deb2f0b98d9acdffdd9abe7 (diff)
downloadconnman-bcae74da8fa2958b3fec9153fc33e41f0e0317bf.tar.gz
connman-bcae74da8fa2958b3fec9153fc33e41f0e0317bf.tar.bz2
connman-bcae74da8fa2958b3fec9153fc33e41f0e0317bf.zip
Imported Upstream version 1.26upstream/1.26
Diffstat (limited to 'gdhcp/client.c')
-rw-r--r--gdhcp/client.c76
1 files changed, 61 insertions, 15 deletions
diff --git a/gdhcp/client.c b/gdhcp/client.c
index 2b7202a4..66c3a90d 100644
--- a/gdhcp/client.c
+++ b/gdhcp/client.c
@@ -47,11 +47,11 @@
#include "common.h"
#include "ipv4ll.h"
-#define DISCOVER_TIMEOUT 3
-#define DISCOVER_RETRIES 10
+#define DISCOVER_TIMEOUT 5
+#define DISCOVER_RETRIES 6
-#define REQUEST_TIMEOUT 3
-#define REQUEST_RETRIES 5
+#define REQUEST_TIMEOUT 5
+#define REQUEST_RETRIES 3
typedef enum _listen_mode {
L_NONE,
@@ -155,6 +155,7 @@ struct _GDHCPClient {
uint32_t expire;
bool retransmit;
struct timeval start_time;
+ bool request_bcast;
};
static inline void debug(GDHCPClient *client, const char *format, ...)
@@ -455,15 +456,26 @@ static int send_discover(GDHCPClient *dhcp_client, uint32_t requested)
add_send_options(dhcp_client, &packet);
+ /*
+ * If we do not get a reply to DISCOVER packet, then we try with
+ * broadcast flag set. So first packet is sent without broadcast flag,
+ * first retry is with broadcast flag, second retry is without it etc.
+ * Reason is various buggy routers/AP that either eat the other or vice
+ * versa. In the receiving side we then find out what kind of packet
+ * the server can send.
+ */
return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
- INADDR_BROADCAST, SERVER_PORT,
- MAC_BCAST_ADDR, dhcp_client->ifindex);
+ INADDR_BROADCAST, SERVER_PORT,
+ MAC_BCAST_ADDR, dhcp_client->ifindex,
+ dhcp_client->retry_times % 2);
}
static int send_request(GDHCPClient *dhcp_client)
{
struct dhcp_packet packet;
- debug(dhcp_client, "sending DHCP request");
+
+ debug(dhcp_client, "sending DHCP request (state %d)",
+ dhcp_client->state);
init_packet(dhcp_client, &packet, DHCPREQUEST);
@@ -484,17 +496,18 @@ static int send_request(GDHCPClient *dhcp_client)
add_send_options(dhcp_client, &packet);
- if (dhcp_client->state == RENEWING) {
+ if (dhcp_client->state == RENEWING || dhcp_client->state == REBINDING)
packet.ciaddr = htonl(dhcp_client->requested_ip);
+ if (dhcp_client->state == RENEWING)
return dhcp_send_kernel_packet(&packet,
dhcp_client->requested_ip, CLIENT_PORT,
dhcp_client->server_ip, SERVER_PORT);
- }
return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
- INADDR_BROADCAST, SERVER_PORT,
- MAC_BCAST_ADDR, dhcp_client->ifindex);
+ INADDR_BROADCAST, SERVER_PORT,
+ MAC_BCAST_ADDR, dhcp_client->ifindex,
+ dhcp_client->request_bcast);
}
static int send_release(GDHCPClient *dhcp_client,
@@ -1130,6 +1143,7 @@ static void remove_option_value(gpointer data)
GList *option_value = data;
g_list_foreach(option_value, remove_value, NULL);
+ g_list_free(option_value);
}
GDHCPClient *g_dhcp_client_new(GDHCPType type,
@@ -1185,6 +1199,7 @@ GDHCPClient *g_dhcp_client_new(GDHCPType type,
dhcp_client->duid_len = 0;
dhcp_client->last_request = time(NULL);
dhcp_client->expire = 0;
+ dhcp_client->request_bcast = false;
*error = G_DHCP_CLIENT_ERROR_NONE;
@@ -1292,7 +1307,8 @@ static bool sanity_check(struct ip_udp_dhcp_packet *packet, int bytes)
return true;
}
-static int dhcp_recv_l2_packet(struct dhcp_packet *dhcp_pkt, int fd)
+static int dhcp_recv_l2_packet(struct dhcp_packet *dhcp_pkt, int fd,
+ struct sockaddr_in *dst_addr)
{
int bytes;
struct ip_udp_dhcp_packet packet;
@@ -1337,6 +1353,8 @@ static int dhcp_recv_l2_packet(struct dhcp_packet *dhcp_pkt, int fd)
if (dhcp_pkt->cookie != htonl(DHCP_MAGIC))
return -1;
+ dst_addr->sin_addr.s_addr = packet.ip.daddr;
+
return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
}
@@ -2047,7 +2065,7 @@ static GList *get_addresses(GDHCPClient *dhcp_client,
memcpy(&dhcp_client->ia_ta, &addr,
sizeof(struct in6_addr));
- if (valid > dhcp_client->expire)
+ if (valid != dhcp_client->expire)
dhcp_client->expire = valid;
}
@@ -2230,6 +2248,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
gpointer user_data)
{
GDHCPClient *dhcp_client = user_data;
+ struct sockaddr_in dst_addr = { 0 };
struct dhcp_packet packet;
struct dhcpv6_packet *packet6 = NULL;
uint8_t *message_type = NULL, *client_id = NULL, *option,
@@ -2256,7 +2275,9 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
if (dhcp_client->listen_mode == L2) {
re = dhcp_recv_l2_packet(&packet,
- dhcp_client->listener_sockfd);
+ dhcp_client->listener_sockfd,
+ &dst_addr);
+ xid = packet.xid;
} else if (dhcp_client->listen_mode == L3) {
if (dhcp_client->type == G_DHCP_IPV6) {
re = dhcpv6_recv_l3_packet(&packet6, buf, sizeof(buf),
@@ -2328,7 +2349,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
return TRUE;
debug(dhcp_client, "received DHCP packet xid 0x%04x "
- "(current state %d)", xid, dhcp_client->state);
+ "(current state %d)", ntohl(xid), dhcp_client->state);
switch (dhcp_client->state) {
case INIT_SELECTING:
@@ -2345,10 +2366,28 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
dhcp_client->state = REQUESTING;
+ if (dst_addr.sin_addr.s_addr == INADDR_BROADCAST)
+ dhcp_client->request_bcast = true;
+ else
+ dhcp_client->request_bcast = false;
+
+ debug(dhcp_client, "init ip %s -> %sadding broadcast flag",
+ inet_ntoa(dst_addr.sin_addr),
+ dhcp_client->request_bcast ? "" : "not ");
+
start_request(dhcp_client);
return TRUE;
case REBOOTING:
+ if (dst_addr.sin_addr.s_addr == INADDR_BROADCAST)
+ dhcp_client->request_bcast = true;
+ else
+ dhcp_client->request_bcast = false;
+
+ debug(dhcp_client, "ip %s -> %sadding broadcast flag",
+ inet_ntoa(dst_addr.sin_addr),
+ dhcp_client->request_bcast ? "" : "not ");
+ /* fall through */
case REQUESTING:
case RENEWING:
case REBINDING:
@@ -2366,6 +2405,12 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
g_free(dhcp_client->assigned_ip);
dhcp_client->assigned_ip = get_ip(packet.yiaddr);
+ if (dhcp_client->state == REBOOTING) {
+ option = dhcp_get_option(&packet,
+ DHCP_SERVER_ID);
+ dhcp_client->server_ip = get_be32(option);
+ }
+
/* Address should be set up here */
if (dhcp_client->lease_available_cb)
dhcp_client->lease_available_cb(dhcp_client,
@@ -2833,6 +2878,7 @@ void g_dhcp_client_stop(GDHCPClient *dhcp_client)
dhcp_client->requested_ip = 0;
dhcp_client->state = RELEASED;
dhcp_client->lease_seconds = 0;
+ dhcp_client->request_bcast = false;
}
GList *g_dhcp_client_get_option(GDHCPClient *dhcp_client,