Increase number of DHCP discover attempts for interoperability
[framework/connectivity/connman.git] / gdhcp / client.c
index 3226392..5c5b426 100644 (file)
@@ -33,7 +33,6 @@
 
 #include <netpacket/packet.h>
 #include <net/ethernet.h>
-#include <net/if_arp.h>
 
 #include <linux/if.h>
 #include <linux/filter.h>
 #include "common.h"
 
 #define DISCOVER_TIMEOUT 3
-#define DISCOVER_RETRIES 3
+#define DISCOVER_RETRIES 10
 
 #define REQUEST_TIMEOUT 3
-#define REQUEST_RETRIES 3
+#define REQUEST_RETRIES 5
 
 typedef enum _listen_mode {
        L_NONE,
@@ -99,7 +98,21 @@ struct _GDHCPClient {
        gpointer debug_data;
 };
 
-static GTimer *timer = NULL;
+static inline void debug(GDHCPClient *client, const char *format, ...)
+{
+       char str[256];
+       va_list ap;
+
+       if (client->debug_func == NULL)
+               return;
+
+       va_start(ap, format);
+
+       if (vsnprintf(str, sizeof(str), format, ap) > 0)
+               client->debug_func(str, client->debug_data);
+
+       va_end(ap);
+}
 
 /* Initialize the packet with the proper defaults */
 static void init_packet(GDHCPClient *dhcp_client,
@@ -151,6 +164,8 @@ static int send_discover(GDHCPClient *dhcp_client, uint32_t requested)
 {
        struct dhcp_packet packet;
 
+       debug(dhcp_client, "sending DHCP discover request");
+
        init_packet(dhcp_client, &packet, DHCPDISCOVER);
 
        packet.xid = dhcp_client->xid;
@@ -176,6 +191,8 @@ static int send_select(GDHCPClient *dhcp_client)
        struct dhcp_packet packet;
        struct in_addr addr;
 
+       debug(dhcp_client, "sending DHCP select request");
+
        init_packet(dhcp_client, &packet, DHCPREQUEST);
 
        packet.xid = dhcp_client->xid;
@@ -199,6 +216,8 @@ static int send_renew(GDHCPClient *dhcp_client)
 {
        struct dhcp_packet packet;
 
+       debug(dhcp_client, "sending DHCP renew request");
+
        init_packet(dhcp_client , &packet, DHCPREQUEST);
        packet.xid = dhcp_client->xid;
        packet.ciaddr = dhcp_client->requested_ip;
@@ -216,6 +235,8 @@ static int send_rebound(GDHCPClient *dhcp_client)
 {
        struct dhcp_packet packet;
 
+       debug(dhcp_client, "sending DHCP rebound request");
+
        init_packet(dhcp_client , &packet, DHCPREQUEST);
        packet.xid = dhcp_client->xid;
        packet.ciaddr = dhcp_client->requested_ip;
@@ -234,6 +255,8 @@ static int send_release(GDHCPClient *dhcp_client,
 {
        struct dhcp_packet packet;
 
+       debug(dhcp_client, "sending DHCP release request");
+
        init_packet(dhcp_client, &packet, DHCPRELEASE);
        packet.xid = rand();
        packet.ciaddr = ciaddr;
@@ -244,70 +267,7 @@ static int send_release(GDHCPClient *dhcp_client,
                                                server, SERVER_PORT);
 }
 
-static gboolean interface_is_up(int index)
-{
-       int sk, err;
-       struct ifreq ifr;
-       gboolean ret = FALSE;
-
-       sk = socket(PF_INET, SOCK_DGRAM, 0);
-       if (sk < 0) {
-               perror("Open socket error");
-               return FALSE;
-       }
 
-       memset(&ifr, 0, sizeof(ifr));
-       ifr.ifr_ifindex = index;
-
-       err = ioctl(sk, SIOCGIFNAME, &ifr);
-       if (err < 0) {
-               perror("Get interface name error");
-               goto done;
-       }
-
-       err = ioctl(sk, SIOCGIFFLAGS, &ifr);
-       if (err < 0) {
-               perror("Get interface flags error");
-               goto done;
-       }
-
-       if (ifr.ifr_flags & IFF_UP)
-               ret = TRUE;
-
-done:
-       close(sk);
-
-       return ret;
-}
-
-static char *get_interface_name(int index)
-{
-       struct ifreq ifr;
-       int sk, err;
-
-       if (index < 0)
-               return NULL;
-
-       sk = socket(PF_INET, SOCK_DGRAM, 0);
-       if (sk < 0) {
-               perror("Open socket error");
-               return NULL;
-       }
-
-       memset(&ifr, 0, sizeof(ifr));
-       ifr.ifr_ifindex = index;
-
-       err = ioctl(sk, SIOCGIFNAME, &ifr);
-       if (err < 0) {
-               perror("Get interface name error");
-               close(sk);
-               return NULL;
-       }
-
-       close(sk);
-
-       return g_strdup(ifr.ifr_name);
-}
 
 static void get_interface_mac_address(int index, uint8_t *mac_address)
 {
@@ -576,6 +536,9 @@ static gboolean request_timeout(gpointer user_data)
 {
        GDHCPClient *dhcp_client = user_data;
 
+       debug(dhcp_client, "request timeout (retries %d)",
+                                       dhcp_client->retry_times);
+
        dhcp_client->retry_times++;
 
        start_request(dhcp_client);
@@ -592,6 +555,9 @@ static int switch_listening_mode(GDHCPClient *dhcp_client,
        GIOChannel *listener_channel;
        int listener_sockfd;
 
+       debug(dhcp_client, "switch listening mode (%d ==> %d)",
+                               dhcp_client->listen_mode, listen_mode);
+
        if (dhcp_client->listen_mode == listen_mode)
                return 0;
 
@@ -641,6 +607,9 @@ static int switch_listening_mode(GDHCPClient *dhcp_client,
 
 static void start_request(GDHCPClient *dhcp_client)
 {
+       debug(dhcp_client, "start request (retries %d)",
+                                       dhcp_client->retry_times);
+
        if (dhcp_client->retry_times == REQUEST_RETRIES) {
                dhcp_client->state = INIT_SELECTING;
 
@@ -686,6 +655,8 @@ static uint32_t get_lease(struct dhcp_packet *packet)
 
 static void restart_dhcp(GDHCPClient *dhcp_client, int retry_times)
 {
+       debug(dhcp_client, "restart DHCP (retries %d)", retry_times);
+
        if (dhcp_client->timeout > 0) {
                g_source_remove(dhcp_client->timeout);
                dhcp_client->timeout = 0;
@@ -702,6 +673,8 @@ static gboolean start_rebound_timeout(gpointer user_data)
 {
        GDHCPClient *dhcp_client = user_data;
 
+       debug(dhcp_client, "start rebound timeout");
+
        switch_listening_mode(dhcp_client, L2);
 
        dhcp_client->lease_seconds >>= 1;
@@ -731,6 +704,8 @@ static gboolean start_rebound_timeout(gpointer user_data)
 
 static void start_rebound(GDHCPClient *dhcp_client)
 {
+       debug(dhcp_client, "start rebound");
+
        dhcp_client->state = REBINDING;
 
        dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
@@ -743,12 +718,8 @@ static void start_rebound(GDHCPClient *dhcp_client)
 static gboolean start_renew_timeout(gpointer user_data)
 {
        GDHCPClient *dhcp_client = user_data;
-       gdouble elapse;
-       gulong microseconds;
-
-       elapse = g_timer_elapsed(timer, &microseconds);
 
-       g_timer_start(timer);
+       debug(dhcp_client, "start renew timeout");
 
        dhcp_client->state = RENEWING;
 
@@ -773,13 +744,11 @@ static gboolean start_renew_timeout(gpointer user_data)
 
 static void start_bound(GDHCPClient *dhcp_client)
 {
-       dhcp_client->state = BOUND;
+       debug(dhcp_client, "start bound");
 
-       if (timer == NULL)
-               timer = g_timer_new();
+       dhcp_client->state = BOUND;
 
-       dhcp_client->timeout =
-                       g_timeout_add_seconds_full(G_PRIORITY_HIGH,
+       dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
                                        dhcp_client->lease_seconds >> 1,
                                        start_renew_timeout, dhcp_client,
                                                        NULL);
@@ -789,6 +758,8 @@ static gboolean restart_dhcp_timeout(gpointer user_data)
 {
        GDHCPClient *dhcp_client = user_data;
 
+       debug(dhcp_client, "restart DHCP timeout");
+
        dhcp_client->ack_retry_times++;
 
        restart_dhcp(dhcp_client, dhcp_client->ack_retry_times);
@@ -829,9 +800,13 @@ static char *malloc_option_value_string(uint8_t *option, GDHCPOptionType type)
        len = option[OPT_LEN - OPT_DATA];
        type &= OPTION_TYPE_MASK;
        optlen = dhcp_option_lengths[type];
+       if (optlen == 0)
+               return NULL;
        upper_length = len_of_option_as_string[type] *
                        ((unsigned)len / (unsigned)optlen);
        dest = ret = malloc(upper_length + 1);
+       if (ret == NULL)
+               return NULL;
 
        while (len >= optlen) {
                switch (type) {
@@ -874,15 +849,18 @@ static GList *get_option_value_list(char *value)
        char *pos = value;
        GList *list = NULL;
 
+       if (pos == NULL)
+               return NULL;
+
        while ((pos = strchr(pos, ' ')) != NULL) {
                *pos = '\0';
 
-               list =  g_list_append(list, g_strdup(value));
+               list = g_list_append(list, g_strdup(value));
 
                value = ++pos;
        }
 
-       list =  g_list_append(list, g_strdup(value));
+       list = g_list_append(list, g_strdup(value));
 
        return list;
 }
@@ -908,6 +886,9 @@ static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet)
                type =  dhcp_get_code_type(code);
 
                option_value = malloc_option_value_string(option, type);
+               if (option_value == NULL)
+                       g_hash_table_remove(dhcp_client->code_value_hash,
+                                               GINT_TO_POINTER((int) code));
 
                value_list = get_option_value_list(option_value);
 
@@ -956,6 +937,9 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
                /* No message type option, ignore pakcage */
                return TRUE;
 
+       debug(dhcp_client, "received DHCP packet (current state %d)",
+                                                       dhcp_client->state);
+
        switch (dhcp_client->state) {
        case INIT_SELECTING:
                if (*message_type != DHCPOFFER)
@@ -1018,6 +1002,9 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
                break;
        }
 
+       debug(dhcp_client, "processed DHCP packet (new state %d)",
+                                                       dhcp_client->state);
+
        return TRUE;
 }
 
@@ -1163,32 +1150,15 @@ static uint8_t *alloc_dhcp_option(int code, const char *str, int extra)
        return storage;
 }
 
-static const char *get_hostname(const char *host)
-{
-       char local_host_name[HOST_NAME_MAX + 1];
-
-       if (g_strcmp0("<hostname>", host) != 0)
-               return g_strdup(host);
-
-       if (gethostname(local_host_name, HOST_NAME_MAX) != 0)
-               return NULL;
-
-       local_host_name[HOST_NAME_MAX] = 0;
-
-       return g_strdup(local_host_name);
-}
-
 /* Now only support send hostname */
 GDHCPClientError g_dhcp_client_set_send(GDHCPClient *dhcp_client,
                unsigned char option_code, const char *option_value)
 {
        uint8_t *binary_option;
-       const char *hostname;
 
-       if (option_code == DHCP_HOST_NAME) {
-               hostname = get_hostname(option_value);
-
-               binary_option = alloc_dhcp_option(option_code, hostname, 0);
+       if (option_code == G_DHCP_HOST_NAME && option_value != NULL) {
+               binary_option = alloc_dhcp_option(option_code,
+                                                       option_value, 0);
 
                g_hash_table_insert(dhcp_client->send_value_hash,
                        GINT_TO_POINTER((int) option_code), binary_option);
@@ -1197,13 +1167,21 @@ GDHCPClientError g_dhcp_client_set_send(GDHCPClient *dhcp_client,
        return G_DHCP_CLIENT_ERROR_NONE;
 }
 
-void g_dhcp_client_ref(GDHCPClient *dhcp_client)
+GDHCPClient *g_dhcp_client_ref(GDHCPClient *dhcp_client)
 {
+       if (dhcp_client == NULL)
+               return NULL;
+
        g_atomic_int_inc(&dhcp_client->ref_count);
+
+       return dhcp_client;
 }
 
 void g_dhcp_client_unref(GDHCPClient *dhcp_client)
 {
+       if (dhcp_client == NULL)
+               return;
+
        if (g_atomic_int_dec_and_test(&dhcp_client->ref_count) == FALSE)
                return;
 
@@ -1222,8 +1200,11 @@ void g_dhcp_client_unref(GDHCPClient *dhcp_client)
 }
 
 void g_dhcp_client_set_debug(GDHCPClient *dhcp_client,
-                               GDHCPDebugFunc func, gpointer data)
+                               GDHCPDebugFunc func, gpointer user_data)
 {
+       if (dhcp_client == NULL)
+               return;
+
        dhcp_client->debug_func = func;
-       dhcp_client->debug_data = data;
+       dhcp_client->debug_data = user_data;
 }