Merge tag 'upstream/1.40' into tizen.
[platform/upstream/connman.git] / gdhcp / client.c
old mode 100644 (file)
new mode 100755 (executable)
index 3e67fcd..cc0379e
@@ -23,7 +23,6 @@
 #include <config.h>
 #endif
 
-#define _GNU_SOURCE
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
 
 #include <glib.h>
 
+#include "../src/connman.h"
+#include "../src/shared/arp.h"
 #include "gdhcp.h"
 #include "common.h"
-#include "ipv4ll.h"
 
 #define DISCOVER_TIMEOUT 5
 #define DISCOVER_RETRIES 6
 
+#if defined TIZEN_EXT
+#define REQUEST_TIMEOUT 1
+#else
 #define REQUEST_TIMEOUT 5
+#endif
 #define REQUEST_RETRIES 3
 
+#if defined TIZEN_EXT
+#define DISCOVER_TIMEOUT_WIFI 1
+#define DISCOVER_RETRIES_WIFI 10
+static int dhcp_discover_timeout = DISCOVER_TIMEOUT_WIFI;
+static int dhcp_discover_max_retry = DISCOVER_RETRIES_WIFI;
+
+void set_dhcp_discover_timeout(int timeout_value)
+{
+       dhcp_discover_timeout = timeout_value;
+}
+
+void set_dhcp_discover_retry_count(int retry_count)
+{
+       dhcp_discover_max_retry = retry_count;
+}
+#endif
+
 typedef enum _listen_mode {
        L_NONE,
        L2,
@@ -65,6 +86,7 @@ typedef enum _dhcp_client_state {
        REBOOTING,
        REQUESTING,
        BOUND,
+       DECLINED,
        RENEWING,
        REBINDING,
        RELEASED,
@@ -109,6 +131,7 @@ struct _GDHCPClient {
        GList *request_list;
        GHashTable *code_value_hash;
        GHashTable *send_value_hash;
+       GHashTable *secs_bcast_hash;
        GDHCPClientEventFunc lease_available_cb;
        gpointer lease_available_data;
        GDHCPClientEventFunc ipv4ll_available_cb;
@@ -156,6 +179,10 @@ struct _GDHCPClient {
        bool retransmit;
        struct timeval start_time;
        bool request_bcast;
+#if defined TIZEN_EXT
+       uint32_t dhcp_lease_seconds;
+       gboolean init_reboot;
+#endif
 };
 
 static inline void debug(GDHCPClient *client, const char *format, ...)
@@ -464,10 +491,40 @@ static int send_discover(GDHCPClient *dhcp_client, uint32_t requested)
         * versa. In the receiving side we then find out what kind of packet
         * the server can send.
         */
+       dhcp_client->request_bcast = dhcp_client->retry_times % 2;
+
+       if (dhcp_client->request_bcast)
+               g_hash_table_add(dhcp_client->secs_bcast_hash,
+                               GINT_TO_POINTER(packet.secs));
+
        return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
                                INADDR_BROADCAST, SERVER_PORT,
                                MAC_BCAST_ADDR, dhcp_client->ifindex,
-                               dhcp_client->retry_times % 2);
+                               dhcp_client->request_bcast);
+}
+
+int g_dhcp_client_decline(GDHCPClient *dhcp_client, uint32_t requested)
+{
+       struct dhcp_packet packet;
+
+       dhcp_client->state = DECLINED;
+       dhcp_client->retry_times = 0;
+
+       debug(dhcp_client, "sending DHCP decline");
+
+       init_packet(dhcp_client, &packet, DHCPDECLINE);
+
+       packet.xid = dhcp_client->xid;
+       packet.secs = dhcp_attempt_secs(dhcp_client);
+
+       if (requested)
+               dhcp_add_option_uint32(&packet, DHCP_REQUESTED_IP, requested);
+
+       add_send_options(dhcp_client, &packet);
+
+       return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
+                               INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR,
+                               dhcp_client->ifindex, true);
 }
 
 static int send_request(GDHCPClient *dhcp_client)
@@ -480,6 +537,9 @@ static int send_request(GDHCPClient *dhcp_client)
        init_packet(dhcp_client, &packet, DHCPREQUEST);
 
        packet.xid = dhcp_client->xid;
+#if defined TIZEN_EXT
+       if (dhcp_client->init_reboot != TRUE)
+#endif
        packet.secs = dhcp_attempt_secs(dhcp_client);
 
        if (dhcp_client->state == REQUESTING || dhcp_client->state == REBOOTING)
@@ -502,7 +562,8 @@ static int send_request(GDHCPClient *dhcp_client)
        if (dhcp_client->state == RENEWING)
                return dhcp_send_kernel_packet(&packet,
                                dhcp_client->requested_ip, CLIENT_PORT,
-                               dhcp_client->server_ip, SERVER_PORT);
+                               dhcp_client->server_ip, SERVER_PORT,
+                               dhcp_client->interface);
 
        return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
                                INADDR_BROADCAST, SERVER_PORT,
@@ -519,14 +580,15 @@ static int send_release(GDHCPClient *dhcp_client,
        debug(dhcp_client, "sending DHCP release request");
 
        init_packet(dhcp_client, &packet, DHCPRELEASE);
-       dhcp_get_random(&rand);
+       __connman_util_get_random(&rand);
        packet.xid = rand;
        packet.ciaddr = htonl(ciaddr);
 
        dhcp_add_option_uint32(&packet, DHCP_SERVER_ID, server);
 
        return dhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT,
-                                               server, SERVER_PORT);
+                                               server, SERVER_PORT,
+                                               dhcp_client->interface);
 }
 
 static gboolean ipv4ll_probe_timeout(gpointer dhcp_data);
@@ -542,7 +604,7 @@ static gboolean send_probe_packet(gpointer dhcp_data)
        /* if requested_ip is not valid, pick a new address*/
        if (dhcp_client->requested_ip == 0) {
                debug(dhcp_client, "pick a new random address");
-               dhcp_client->requested_ip = ipv4ll_random_ip();
+               dhcp_client->requested_ip = arp_random_ip();
        }
 
        debug(dhcp_client, "sending IPV4LL probe request");
@@ -551,12 +613,12 @@ static gboolean send_probe_packet(gpointer dhcp_data)
                dhcp_client->state = IPV4LL_PROBE;
                switch_listening_mode(dhcp_client, L_ARP);
        }
-       ipv4ll_send_arp_packet(dhcp_client->mac_address, 0,
+       arp_send_packet(dhcp_client->mac_address, 0,
                        dhcp_client->requested_ip, dhcp_client->ifindex);
 
        if (dhcp_client->retry_times < PROBE_NUM) {
                /*add a random timeout in range of PROBE_MIN to PROBE_MAX*/
-               timeout = ipv4ll_random_delay_ms(PROBE_MAX-PROBE_MIN);
+               timeout = __connman_util_random_delay_ms(PROBE_MAX-PROBE_MIN);
                timeout += PROBE_MIN*1000;
        } else
                timeout = (ANNOUNCE_WAIT * 1000);
@@ -580,7 +642,7 @@ static gboolean send_announce_packet(gpointer dhcp_data)
 
        debug(dhcp_client, "sending IPV4LL announce request");
 
-       ipv4ll_send_arp_packet(dhcp_client->mac_address,
+       arp_send_packet(dhcp_client->mac_address,
                                dhcp_client->requested_ip,
                                dhcp_client->requested_ip,
                                dhcp_client->ifindex);
@@ -605,38 +667,6 @@ static gboolean send_announce_packet(gpointer dhcp_data)
        return TRUE;
 }
 
-static void get_interface_mac_address(int index, uint8_t *mac_address)
-{
-       struct ifreq ifr;
-       int sk, err;
-
-       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0) {
-               perror("Open socket error");
-               return;
-       }
-
-       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, SIOCGIFHWADDR, &ifr);
-       if (err < 0) {
-               perror("Get mac address error");
-               goto done;
-       }
-
-       memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
-
-done:
-       close(sk);
-}
-
 void g_dhcpv6_client_set_retransmit(GDHCPClient *dhcp_client)
 {
        if (!dhcp_client)
@@ -667,7 +697,7 @@ int g_dhcpv6_create_duid(GDHCPDuidType duid_type, int index, int type,
 
                (*duid)[0] = 0;
                (*duid)[1] = 1;
-               get_interface_mac_address(index, &(*duid)[2 + 2 + 4]);
+               __connman_inet_get_interface_mac_address(index, &(*duid)[2 + 2 + 4]);
                (*duid)[2] = 0;
                (*duid)[3] = type;
                duid_time = time(NULL) - DUID_TIME_EPOCH;
@@ -686,7 +716,7 @@ int g_dhcpv6_create_duid(GDHCPDuidType duid_type, int index, int type,
 
                (*duid)[0] = 0;
                (*duid)[1] = 3;
-               get_interface_mac_address(index, &(*duid)[2 + 2]);
+               __connman_inet_get_interface_mac_address(index, &(*duid)[2 + 2]);
                (*duid)[2] = 0;
                (*duid)[3] = type;
                break;
@@ -811,7 +841,7 @@ void g_dhcpv6_client_create_iaid(GDHCPClient *dhcp_client, int index,
 {
        uint8_t buf[6];
 
-       get_interface_mac_address(index, buf);
+       __connman_inet_get_interface_mac_address(index, buf);
 
        memcpy(iaid, &buf[2], 4);
        dhcp_client->iaid = iaid[0] << 24 |
@@ -1178,7 +1208,7 @@ GDHCPClient *g_dhcp_client_new(GDHCPType type,
                goto error;
        }
 
-       get_interface_mac_address(ifindex, dhcp_client->mac_address);
+       __connman_inet_get_interface_mac_address(ifindex, dhcp_client->mac_address);
 
        dhcp_client->listener_sockfd = -1;
        dhcp_client->listen_mode = L_NONE;
@@ -1198,6 +1228,8 @@ GDHCPClient *g_dhcp_client_new(GDHCPType type,
                                g_direct_equal, NULL, remove_option_value);
        dhcp_client->send_value_hash = g_hash_table_new_full(g_direct_hash,
                                g_direct_equal, NULL, g_free);
+       dhcp_client->secs_bcast_hash = g_hash_table_new(g_direct_hash,
+                               g_direct_equal);
        dhcp_client->request_list = NULL;
        dhcp_client->require_list = NULL;
        dhcp_client->duid = NULL;
@@ -1373,10 +1405,10 @@ static void ipv4ll_start(GDHCPClient *dhcp_client)
        dhcp_client->retry_times = 0;
        dhcp_client->requested_ip = 0;
 
-       dhcp_client->requested_ip = ipv4ll_random_ip();
+       dhcp_client->requested_ip = arp_random_ip();
 
        /*first wait a random delay to avoid storm of arp request on boot*/
-       timeout = ipv4ll_random_delay_ms(PROBE_WAIT);
+       timeout = __connman_util_random_delay_ms(PROBE_WAIT);
 
        dhcp_client->retry_times++;
        dhcp_client->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
@@ -1413,6 +1445,7 @@ static int ipv4ll_recv_arp_packet(GDHCPClient *dhcp_client)
        uint32_t ip_requested;
        int source_conflict;
        int target_conflict;
+       guint timeout_ms;
 
        memset(&arp, 0, sizeof(arp));
        bytes = read(dhcp_client->listener_sockfd, &arp, sizeof(arp));
@@ -1423,6 +1456,9 @@ static int ipv4ll_recv_arp_packet(GDHCPClient *dhcp_client)
                        arp.arp_op != htons(ARPOP_REQUEST))
                return -EINVAL;
 
+       if (memcmp(arp.arp_sha, dhcp_client->mac_address, ETH_ALEN) == 0)
+               return 0;
+
        ip_requested = htonl(dhcp_client->requested_ip);
        source_conflict = !memcmp(arp.arp_spa, &ip_requested,
                                                sizeof(ip_requested));
@@ -1458,23 +1494,20 @@ static int ipv4ll_recv_arp_packet(GDHCPClient *dhcp_client)
 
        ipv4ll_stop(dhcp_client);
 
-       if (dhcp_client->conflicts < MAX_CONFLICTS) {
-               /*restart whole state machine*/
-               dhcp_client->retry_times++;
-               dhcp_client->timeout =
-                       g_timeout_add_full(G_PRIORITY_HIGH,
-                                       ipv4ll_random_delay_ms(PROBE_WAIT),
-                                       send_probe_packet,
-                                       dhcp_client,
-                                       NULL);
-       }
-       /* Here we got a lot of conflicts, RFC3927 states that we have
+       /* If we got a lot of conflicts, RFC3927 states that we have
         * to wait RATE_LIMIT_INTERVAL before retrying,
-        * but we just report failure.
         */
-       else if (dhcp_client->no_lease_cb)
-                       dhcp_client->no_lease_cb(dhcp_client,
-                                               dhcp_client->no_lease_data);
+       if (dhcp_client->conflicts < MAX_CONFLICTS)
+               timeout_ms = __connman_util_random_delay_ms(PROBE_WAIT);
+       else
+               timeout_ms = RATE_LIMIT_INTERVAL * 1000;
+       dhcp_client->retry_times++;
+       dhcp_client->timeout =
+               g_timeout_add_full(G_PRIORITY_HIGH,
+                               timeout_ms,
+                               send_probe_packet,
+                               dhcp_client,
+                               NULL);
 
        return 0;
 }
@@ -1516,6 +1549,21 @@ static gboolean request_timeout(gpointer user_data)
 {
        GDHCPClient *dhcp_client = user_data;
 
+#if defined TIZEN_EXT
+       if (dhcp_client->init_reboot) {
+               debug(dhcp_client, "DHCPREQUEST of INIT-REBOOT has failed");
+
+               /* Start DHCPDISCOVERY when DHCPREQUEST of INIT-REBOOT has failed */
+               g_dhcp_client_set_address_known(dhcp_client, FALSE);
+
+               dhcp_client->retry_times = 0;
+               dhcp_client->requested_ip = 0;
+
+               g_dhcp_client_start(dhcp_client, dhcp_client->last_address);
+
+               return FALSE;
+       }
+#endif
        debug(dhcp_client, "request timeout (retries %d)",
                                        dhcp_client->retry_times);
 
@@ -1526,6 +1574,12 @@ static gboolean request_timeout(gpointer user_data)
        return FALSE;
 }
 
+static void listener_watch_destroy(gpointer user_data)
+{
+       GDHCPClient *dhcp_client = user_data;
+       g_dhcp_client_unref(dhcp_client);
+}
+
 static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
                                                        gpointer user_data);
 
@@ -1564,7 +1618,7 @@ static int switch_listening_mode(GDHCPClient *dhcp_client,
                                                        dhcp_client->interface,
                                                        AF_INET);
        } else if (listen_mode == L_ARP)
-               listener_sockfd = ipv4ll_arp_socket(dhcp_client->ifindex);
+               listener_sockfd = arp_socket(dhcp_client->ifindex);
        else
                return -EIO;
 
@@ -1585,8 +1639,8 @@ static int switch_listening_mode(GDHCPClient *dhcp_client,
        dhcp_client->listener_watch =
                        g_io_add_watch_full(listener_channel, G_PRIORITY_HIGH,
                                G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
-                                               listener_event, dhcp_client,
-                                                               NULL);
+                                               listener_event, g_dhcp_client_ref(dhcp_client),
+                                                               listener_watch_destroy);
        g_io_channel_unref(listener_channel);
 
        return 0;
@@ -1618,12 +1672,12 @@ static void start_request(GDHCPClient *dhcp_client)
                                                        NULL);
 }
 
-static uint32_t get_lease(struct dhcp_packet *packet)
+static uint32_t get_lease(struct dhcp_packet *packet, uint16_t packet_len)
 {
        uint8_t *option;
        uint32_t lease_seconds;
 
-       option = dhcp_get_option(packet, DHCP_LEASE_TIME);
+       option = dhcp_get_option(packet, packet_len, DHCP_LEASE_TIME);
        if (!option)
                return 3600;
 
@@ -1684,7 +1738,7 @@ static gboolean continue_rebound(gpointer user_data)
        /*recalculate remaining rebind time*/
        dhcp_client->T2 >>= 1;
        if (dhcp_client->T2 > 60) {
-               dhcp_get_random(&rand);
+               __connman_util_get_random(&rand);
                dhcp_client->t2_timeout =
                        g_timeout_add_full(G_PRIORITY_HIGH,
                                        dhcp_client->T2 * 1000 + (rand % 2000) - 1000,
@@ -1732,7 +1786,7 @@ static gboolean continue_renew (gpointer user_data)
        dhcp_client->T1 >>= 1;
 
        if (dhcp_client->T1 > 60) {
-               dhcp_get_random(&rand);
+               __connman_util_get_random(&rand);
                dhcp_client->t1_timeout = g_timeout_add_full(G_PRIORITY_HIGH,
                                dhcp_client->T1 * 1000 + (rand % 2000) - 1000,
                                continue_renew,
@@ -2215,7 +2269,8 @@ static void get_dhcpv6_request(GDHCPClient *dhcp_client,
        }
 }
 
-static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet)
+static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet,
+               uint16_t packet_len)
 {
        GDHCPOptionType type;
        GList *list, *value_list;
@@ -2226,7 +2281,7 @@ static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet)
        for (list = dhcp_client->request_list; list; list = list->next) {
                code = (uint8_t) GPOINTER_TO_INT(list->data);
 
-               option = dhcp_get_option(packet, code);
+               option = dhcp_get_option(packet, packet_len, code);
                if (!option) {
                        g_hash_table_remove(dhcp_client->code_value_hash,
                                                GINT_TO_POINTER((int) code));
@@ -2258,7 +2313,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
 {
        GDHCPClient *dhcp_client = user_data;
        struct sockaddr_in dst_addr = { 0 };
-       struct dhcp_packet packet;
+       struct dhcp_packet packet = { 0 };
        struct dhcpv6_packet *packet6 = NULL;
        uint8_t *message_type = NULL, *client_id = NULL, *option,
                *server_id = NULL;
@@ -2272,6 +2327,14 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
 
        if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
                dhcp_client->listener_watch = 0;
+#if defined TIZEN_EXT
+               /* re-register event listener when socket failed */
+               int retry_count = 0;
+               int ret = -1;
+               while (retry_count++ < GIO_SOCKET_RETRY_COUNT && ret < 0)
+                       ret = switch_listening_mode(dhcp_client,
+                                       dhcp_client->type);
+#endif /* defined TIZEN_EXT */
                return FALSE;
        }
 
@@ -2286,6 +2349,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
                re = dhcp_recv_l2_packet(&packet,
                                        dhcp_client->listener_sockfd,
                                        &dst_addr);
+               pkt_len = (uint16_t)(unsigned int)re;
                xid = packet.xid;
        } else if (dhcp_client->listen_mode == L3) {
                if (dhcp_client->type == G_DHCP_IPV6) {
@@ -2350,7 +2414,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
                        dhcp_client->status_code = status;
                }
        } else {
-               message_type = dhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
+               message_type = dhcp_get_option(&packet, pkt_len, DHCP_MESSAGE_TYPE);
                if (!message_type)
                        return TRUE;
        }
@@ -2367,20 +2431,34 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
                dhcp_client->timeout = 0;
                dhcp_client->retry_times = 0;
 
-               option = dhcp_get_option(&packet, DHCP_SERVER_ID);
+               option = dhcp_get_option(&packet, pkt_len, DHCP_SERVER_ID);
                dhcp_client->server_ip = get_be32(option);
                dhcp_client->requested_ip = ntohl(packet.yiaddr);
 
                dhcp_client->state = REQUESTING;
 
-               if (dst_addr.sin_addr.s_addr == INADDR_BROADCAST)
-                       dhcp_client->request_bcast = true;
-               else
-                       dhcp_client->request_bcast = false;
+               /*
+                * RFC2131:
+                *
+                *   If unicasting is not possible, the message MAY be
+                *   sent as an IP broadcast using an IP broadcast address
+                *   (preferably 0xffffffff) as the IP destination address
+                *   and the link-layer broadcast address as the link-layer
+                *   destination address.
+                *
+                * For interoperability reasons, if the response is an IP
+                * broadcast, let's reuse broadcast flag from DHCPDISCOVER
+                * to which the server has responded. Some servers are picky
+                * about this flag.
+                */
+               dhcp_client->request_bcast =
+                       dst_addr.sin_addr.s_addr == INADDR_BROADCAST &&
+                       g_hash_table_contains(dhcp_client->secs_bcast_hash,
+                               GINT_TO_POINTER(packet.secs));
 
-               debug(dhcp_client, "init ip %s -> %sadding broadcast flag",
-                       inet_ntoa(dst_addr.sin_addr),
-                       dhcp_client->request_bcast ? "" : "not ");
+               debug(dhcp_client, "init ip %s secs %hu -> broadcast flag %s",
+                       inet_ntoa(dst_addr.sin_addr), packet.secs,
+                       dhcp_client->request_bcast ? "on" : "off");
 
                start_request(dhcp_client);
 
@@ -2403,9 +2481,13 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
 
                        remove_timeouts(dhcp_client);
 
-                       dhcp_client->lease_seconds = get_lease(&packet);
+                       dhcp_client->lease_seconds = get_lease(&packet, pkt_len);
+
+#if defined TIZEN_EXT
+                       dhcp_client->dhcp_lease_seconds = dhcp_client->lease_seconds;
+#endif
 
-                       get_request(dhcp_client, &packet);
+                       get_request(dhcp_client, &packet, pkt_len);
 
                        switch_listening_mode(dhcp_client, L_NONE);
 
@@ -2413,7 +2495,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
                        dhcp_client->assigned_ip = get_ip(packet.yiaddr);
 
                        if (dhcp_client->state == REBOOTING) {
-                               option = dhcp_get_option(&packet,
+                               option = dhcp_get_option(&packet, pkt_len,
                                                        DHCP_SERVER_ID);
                                dhcp_client->server_ip = get_be32(option);
                        }
@@ -2429,6 +2511,18 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
 
                        remove_timeouts(dhcp_client);
 
+#if defined TIZEN_EXT
+                       if (dhcp_client->init_reboot) {
+                               g_dhcp_client_set_address_known(dhcp_client, FALSE);
+                               dhcp_client->timeout = g_idle_add_full(
+                                                               G_PRIORITY_HIGH,
+                                                               restart_dhcp_timeout,
+                                                               dhcp_client,
+                                                               NULL);
+
+                               break;
+                       }
+#endif
                        dhcp_client->timeout = g_timeout_add_seconds_full(
                                                        G_PRIORITY_HIGH, 3,
                                                        restart_dhcp_timeout,
@@ -2666,6 +2760,11 @@ static gboolean ipv4ll_announce_timeout(gpointer dhcp_data)
        GDHCPClient *dhcp_client = dhcp_data;
        uint32_t ip;
 
+#if defined TIZEN_EXT
+       if (!dhcp_client)
+               return FALSE;
+#endif
+
        debug(dhcp_client, "request timeout (retries %d)",
               dhcp_client->retry_times);
 
@@ -2716,6 +2815,12 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address)
        int re;
        uint32_t addr;
        uint64_t rand;
+       ClientState oldstate = dhcp_client->state;
+
+#if defined TIZEN_EXT
+       int discover_retry = 0;
+       int timeout = 0;
+#endif
 
        remove_timeouts(dhcp_client);
 
@@ -2803,13 +2908,32 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address)
                return 0;
        }
 
+#if defined TIZEN_EXT
+       if (g_ascii_strncasecmp(dhcp_client->interface, "wlan", 4)
+                       == 0) {
+               discover_retry = DISCOVER_RETRIES_WIFI;
+               timeout = DISCOVER_TIMEOUT_WIFI;
+       } else {
+               discover_retry = DISCOVER_RETRIES;
+               timeout = DISCOVER_TIMEOUT;
+       }
+
+       debug(dhcp_client, "[DHCPC] Discover retry/total : [%d]/[%d] timeout [%d]",
+                       dhcp_client->retry_times, discover_retry, timeout);
+#endif
+
+
        if (dhcp_client->type == G_DHCP_IPV4LL) {
                dhcp_client->state = INIT_SELECTING;
                ipv4ll_start(dhcp_client);
                return 0;
        }
 
+#if defined TIZEN_EXT
+       if (dhcp_client->retry_times == discover_retry) {
+#else
        if (dhcp_client->retry_times == DISCOVER_RETRIES) {
+#endif
                if (dhcp_client->no_lease_cb)
                        dhcp_client->no_lease_cb(dhcp_client,
                                                dhcp_client->no_lease_data);
@@ -2826,12 +2950,13 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address)
                if (re != 0)
                        return re;
 
-               dhcp_get_random(&rand);
+               __connman_util_get_random(&rand);
                dhcp_client->xid = rand;
                dhcp_client->start = time(NULL);
+               g_hash_table_remove_all(dhcp_client->secs_bcast_hash);
        }
 
-       if (!last_address) {
+       if (!last_address || oldstate == DECLINED) {
                addr = 0;
        } else {
                addr = ntohl(inet_addr(last_address));
@@ -2852,7 +2977,11 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address)
 
                dhcp_client->timeout = g_timeout_add_seconds_full(
                                                                G_PRIORITY_HIGH,
+#if defined TIZEN_EXT
+                                                               timeout,
+#else
                                                                REQUEST_TIMEOUT,
+#endif
                                                                reboot_timeout,
                                                                dhcp_client,
                                                                NULL);
@@ -2861,7 +2990,11 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address)
        send_discover(dhcp_client, addr);
 
        dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
+#if defined TIZEN_EXT
+                                                       timeout,
+#else
                                                        DISCOVER_TIMEOUT,
+#endif
                                                        discover_timeout,
                                                        dhcp_client,
                                                        NULL);
@@ -3002,9 +3135,20 @@ char *g_dhcp_client_get_server_address(GDHCPClient *dhcp_client)
        if (!dhcp_client)
                return NULL;
 
+#if defined TIZEN_EXT
+       return get_ip(htonl(dhcp_client->server_ip));
+#else
        return get_ip(dhcp_client->server_ip);
+#endif
 }
 
+#if defined TIZEN_EXT
+int g_dhcp_client_get_dhcp_lease_duration(GDHCPClient *dhcp_client)
+{
+       return dhcp_client->dhcp_lease_seconds;
+}
+#endif
+
 char *g_dhcp_client_get_address(GDHCPClient *dhcp_client)
 {
        return g_strdup(dhcp_client->assigned_ip);
@@ -3031,6 +3175,7 @@ char *g_dhcp_client_get_netmask(GDHCPClient *dhcp_client)
        case REBOOTING:
        case REQUESTING:
        case RELEASED:
+       case DECLINED:
        case IPV4LL_PROBE:
        case IPV4LL_ANNOUNCE:
        case INFORMATION_REQ:
@@ -3228,8 +3373,12 @@ void g_dhcp_client_unref(GDHCPClient *dhcp_client)
 
        g_hash_table_destroy(dhcp_client->code_value_hash);
        g_hash_table_destroy(dhcp_client->send_value_hash);
+       g_hash_table_destroy(dhcp_client->secs_bcast_hash);
 
        g_free(dhcp_client);
+#if defined TIZEN_EXT
+       dhcp_client = NULL;
+#endif
 }
 
 void g_dhcp_client_set_debug(GDHCPClient *dhcp_client,
@@ -3265,3 +3414,19 @@ GSList *g_dhcpv6_copy_prefixes(GSList *prefixes)
 
        return copy;
 }
+
+#if defined TIZEN_EXT
+void g_dhcp_client_set_address_known(GDHCPClient *dhcp_client, gboolean known)
+{
+       /* DHCPREQUEST during INIT-REBOOT state (rfc2131)
+        * 4.4.3 Initialization with known network address
+        * 4.3.2 DHCPREQUEST generated during INIT-REBOOT state
+        */
+       debug(dhcp_client, "known network address (%d)", known);
+
+       if (dhcp_client->init_reboot == known)
+               return;
+
+       dhcp_client->init_reboot = known;
+}
+#endif