---
 gdhcp/client.c |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 gdhcp/gdhcp.h  |    3 +++
 src/dhcp.c     |   20 +++++++++++++++++
 3 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/gdhcp/client.c b/gdhcp/client.c
index 7d103ce..c6d3fa4 100644
--- a/gdhcp/client.c
+++ b/gdhcp/client.c
@@ -138,6 +138,8 @@ struct _GDHCPClient {
        gpointer confirm_data;
        GDHCPClientEventFunc decline_cb;
        gpointer decline_data;
+       GDHCPClientEventFunc wake_event_cb;
+       gpointer wake_event_data;
        char *last_address;
        unsigned char *duid;
        int duid_len;
@@ -146,6 +148,8 @@ struct _GDHCPClient {
        uint16_t status_code;
        uint32_t iaid;
        uint32_t T1, T2;
+       uint32_t next_event;
+       bool can_sleep;
        struct in6_addr ia_na;
        struct in6_addr ia_ta;
        time_t last_request;
@@ -271,6 +275,31 @@ static int32_t get_time_diff(struct timeval *tv)
        return hsec;
 }
 
+static void set_wake(GDHCPClient *dhcp_client, uint32_t timeout)
+{
+       dhcp_client->next_event = timeout + time(NULL);
+       dhcp_client->can_sleep = false;
+       if (dhcp_client->wake_event_cb)
+               dhcp_client->wake_event_cb(dhcp_client,
+                               dhcp_client->wake_event_data);
+}
+
+static void release_wake(GDHCPClient *dhcp_client, uint32_t timeout)
+{
+       dhcp_client->next_event = timeout + time(NULL);
+       dhcp_client->can_sleep = true;
+       if (dhcp_client->wake_event_cb)
+               dhcp_client->wake_event_cb(dhcp_client,
+                               dhcp_client->wake_event_data);
+}
+
+bool g_dhcp_get_next_event(GDHCPClient *dhcp_client, time_t *next_event)
+{
+       *next_event = dhcp_client->next_event;
+
+       return dhcp_client->can_sleep;
+}
+
 static void add_dhcpv6_request_options(GDHCPClient *dhcp_client,
                                struct dhcpv6_packet *packet,
                                unsigned char *buf, int max_buf,
@@ -585,6 +614,7 @@ static gboolean send_announce_packet(gpointer dhcp_data)
                                                ipv4ll_defend_timeout,
                                                dhcp_client,
                                                NULL);
+               set_wake(dhcp_client, DEFEND_INTERVAL);
                return TRUE;
        } else
                dhcp_client->timeout =
@@ -593,6 +623,7 @@ static gboolean send_announce_packet(gpointer dhcp_data)
                                                ipv4ll_announce_timeout,
                                                dhcp_client,
                                                NULL);
+       set_wake(dhcp_client, ANNOUNCE_INTERVAL);
        return TRUE;
 }
 
@@ -1179,6 +1210,7 @@ GDHCPClient *g_dhcp_client_new(GDHCPType type,
        dhcp_client->lease_lost_cb = NULL;
        dhcp_client->ipv4ll_lost_cb = NULL;
        dhcp_client->address_conflict_cb = NULL;
+       dhcp_client->wake_event_cb = NULL;
        dhcp_client->listener_watch = 0;
        dhcp_client->retry_times = 0;
        dhcp_client->ack_retry_times = 0;
@@ -1657,6 +1689,10 @@ static gboolean start_rebound_timeout(gpointer user_data)
 
        dhcp_client->expire >>= 1;
 
+       if (dhcp_client->timeout > 0){
+               g_source_remove(dhcp_client->timeout);
+       }
+
        /* We need to have enough time to receive ACK package*/
        if (dhcp_client->expire <= 60) {
 
@@ -1673,6 +1709,7 @@ static gboolean start_rebound_timeout(gpointer user_data)
                                                start_rebound,
                                                dhcp_client,
                                                NULL);
+               release_wake(dhcp_client, dhcp_client->expire);
        }
 
        return false;
@@ -1696,7 +1733,7 @@ static gboolean start_rebound(gpointer user_data)
                        start_rebound_timeout,
                        dhcp_client,
                        NULL);
-
+       set_wake(dhcp_client, REQUEST_TIMEOUT);
        return FALSE;
 }
 
@@ -1708,6 +1745,10 @@ static gboolean start_renew_request_timeout(gpointer 
user_data)
 
        dhcp_client->T2>>=1;
 
+       if (dhcp_client->timeout > 0){
+               g_source_remove(dhcp_client->timeout);
+       }
+
        if (dhcp_client->T2 <= 60)
        {
                debug(dhcp_client, "renew request timeout");
@@ -1724,6 +1765,7 @@ static gboolean start_renew_request_timeout(gpointer 
user_data)
                                start_renew,
                                dhcp_client,
                                NULL);
+               release_wake(dhcp_client, dhcp_client->T2);
        }
 
        return false;
@@ -1739,8 +1781,10 @@ static gboolean start_renew(gpointer user_data)
 
        switch_listening_mode(dhcp_client, L3);
 
-       if (dhcp_client->timeout > 0)
+       if (dhcp_client->timeout > 0){
                g_source_remove(dhcp_client->timeout);
+               dhcp_client->timeout = 0;
+       }
 
        send_renew(dhcp_client);
 
@@ -1751,6 +1795,7 @@ static gboolean start_renew(gpointer user_data)
                                start_renew_request_timeout,
                                dhcp_client,
                                NULL);
+       set_wake(dhcp_client, REQUEST_TIMEOUT);
 
        return FALSE;
 }
@@ -1761,8 +1806,9 @@ static void start_bound(GDHCPClient *dhcp_client)
 
        dhcp_client->state = BOUND;
 
-       if (dhcp_client->timeout > 0)
+       if (dhcp_client->timeout > 0){
                g_source_remove(dhcp_client->timeout);
+       }
 
        /* TODO: T1 and T2 should be set through options instead of
         * defaults as they are here, also note that the actual value
@@ -1777,6 +1823,7 @@ static void start_bound(GDHCPClient *dhcp_client)
                                        dhcp_client->T1,
                                        start_renew, dhcp_client,
                                                        NULL);
+       release_wake(dhcp_client, dhcp_client->T1);
 }
 
 static gboolean restart_dhcp_timeout(gpointer user_data)
@@ -2349,6 +2396,10 @@ static gboolean listener_event(GIOChannel *channel, 
GIOCondition condition,
                g_source_remove(dhcp_client->timeout);
                dhcp_client->timeout = 0;
                dhcp_client->retry_times = 0;
+               dhcp_client->T1 = 0;
+               dhcp_client->T2 = 0;
+               dhcp_client->expire = 0;
+               dhcp_client->next_event= 0;
 
                option = dhcp_get_option(&packet, DHCP_SERVER_ID);
                dhcp_client->server_ip = get_be32(option);
@@ -2365,8 +2416,9 @@ static gboolean listener_event(GIOChannel *channel, 
GIOCondition condition,
                if (*message_type == DHCPACK) {
                        dhcp_client->retry_times = 0;
 
-                       if (dhcp_client->timeout > 0)
+                       if (dhcp_client->timeout > 0){
                                g_source_remove(dhcp_client->timeout);
+                       }
                        dhcp_client->timeout = 0;
 
                        dhcp_client->lease_seconds = get_lease(&packet);
@@ -2395,6 +2447,7 @@ static gboolean listener_event(GIOChannel *channel, 
GIOCondition condition,
                                                        restart_dhcp_timeout,
                                                        dhcp_client,
                                                        NULL);
+                       set_wake(dhcp_client,3);
                }
 
                break;
@@ -2789,6 +2842,7 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const 
char *last_address)
                                                        discover_timeout,
                                                        dhcp_client,
                                                        NULL);
+               set_wake(dhcp_client, DISCOVER_TIMEOUT);
        return 0;
 }
 
@@ -2803,6 +2857,7 @@ void g_dhcp_client_stop(GDHCPClient *dhcp_client)
                                        dhcp_client->requested_ip);
 
        if (dhcp_client->timeout > 0) {
+               set_wake(dhcp_client, 1);
                g_source_remove(dhcp_client->timeout);
                dhcp_client->timeout = 0;
        }
@@ -2917,6 +2972,10 @@ void g_dhcp_client_register_event(GDHCPClient 
*dhcp_client,
                dhcp_client->decline_cb = func;
                dhcp_client->decline_data = data;
                return;
+       case G_DHCP_CLIENT_EVENT_WAKE_EVENT:
+               dhcp_client->wake_event_cb = func;
+               dhcp_client->wake_event_data= data;
+               return;
        }
 }
 
diff --git a/gdhcp/gdhcp.h b/gdhcp/gdhcp.h
index 0d79361..26b1287 100644
--- a/gdhcp/gdhcp.h
+++ b/gdhcp/gdhcp.h
@@ -63,6 +63,7 @@ typedef enum {
        G_DHCP_CLIENT_EVENT_RELEASE,
        G_DHCP_CLIENT_EVENT_CONFIRM,
        G_DHCP_CLIENT_EVENT_DECLINE,
+       G_DHCP_CLIENT_EVENT_WAKE_EVENT,
 } GDHCPClientEvent;
 
 typedef enum {
@@ -169,6 +170,8 @@ gboolean g_dhcpv6_client_clear_send(GDHCPClient 
*dhcp_client, uint16_t code);
 void g_dhcpv6_client_set_send(GDHCPClient *dhcp_client, uint16_t option_code,
                        uint8_t *option_value, uint16_t option_len);
 uint16_t g_dhcpv6_client_get_status(GDHCPClient *dhcp_client);
+bool g_dhcp_get_next_event(GDHCPClient *dhcp_client, time_t *next_event);
+
 int g_dhcpv6_client_set_oro(GDHCPClient *dhcp_client, int args, ...);
 void g_dhcpv6_client_create_iaid(GDHCPClient *dhcp_client, int index,
                                unsigned char *iaid);
diff --git a/src/dhcp.c b/src/dhcp.c
index 2193e4d..680eae4 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -163,6 +163,7 @@ static void ipv4ll_stop_client(struct connman_dhcp *dhcp)
 
 static void ipv4ll_lost_cb(GDHCPClient *dhcp_client, gpointer user_data);
 static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer 
user_data);
+static void wake_event_cb(GDHCPClient *dhcp_client, gpointer user_data);
 
 static int ipv4ll_start_client(struct connman_dhcp *dhcp)
 {
@@ -199,6 +200,10 @@ static int ipv4ll_start_client(struct connman_dhcp *dhcp)
                        G_DHCP_CLIENT_EVENT_IPV4LL_LOST, ipv4ll_lost_cb, dhcp);
 
        g_dhcp_client_register_event(ipv4ll_client,
+                       G_DHCP_CLIENT_EVENT_WAKE_EVENT,
+                                               wake_event_cb, dhcp);
+
+       g_dhcp_client_register_event(ipv4ll_client,
                        G_DHCP_CLIENT_EVENT_IPV4LL_AVAILABLE,
                                                ipv4ll_available_cb, dhcp);
 
@@ -278,6 +283,17 @@ static void ipv4ll_lost_cb(GDHCPClient *dhcp_client, 
gpointer user_data)
        dhcp_invalidate(dhcp, true);
 }
 
+static void wake_event_cb(GDHCPClient *dhcp_client, gpointer user_data)
+{
+       struct connman_dhcp *dhcp = user_data;
+       time_t valid_until;
+       bool can_sleep;
+
+       can_sleep = g_dhcp_get_next_event(dhcp_client, &valid_until);
+       DBG("can_sleep: %d until: %lld", can_sleep, (long long)valid_until);
+
+       __connman_notifier_sleep_event(dhcp,can_sleep, valid_until);
+}
 static bool compare_string_arrays(char **array_a, char **array_b)
 {
        int i;
@@ -543,6 +559,10 @@ static int dhcp_request(struct connman_dhcp *dhcp)
                                                lease_available_cb, dhcp);
 
        g_dhcp_client_register_event(dhcp_client,
+                       G_DHCP_CLIENT_EVENT_WAKE_EVENT,
+                                           wake_event_cb, dhcp);
+
+       g_dhcp_client_register_event(dhcp_client,
                        G_DHCP_CLIENT_EVENT_LEASE_LOST, lease_lost_cb, dhcp);
 
        g_dhcp_client_register_event(dhcp_client,
-- 
1.7.9.5

_______________________________________________
connman mailing list
[email protected]
https://lists.connman.net/mailman/listinfo/connman

Reply via email to