]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Use monotonic clock for relative time for eloop if available
authorJohannes Berg <johannes.berg@intel.com>
Wed, 20 Nov 2013 10:01:09 +0000 (11:01 +0100)
committerJouni Malinen <j@w1.fi>
Wed, 20 Nov 2013 21:52:56 +0000 (23:52 +0200)
Relative time shouldn't be calculated based on gettimeofday
because that clock can jump (e.g., when the time is adjusted
by the system administrator.)

On systems where that is available, use CLOCK_BOOTTIME (on
fairly recent Linux systems, this clock takes into account
the time spend suspended) or CLOCK_MONOTONIC (on Linux and
some POSIX systems, this clock is just freely running with
no adjustments.)

Reported-by: Holger Schurig <holgerschurig@gmail.com>
Signed-hostap: Johannes Berg <johannes.berg@intel.com>

12 files changed:
hostapd/Makefile
src/utils/eloop.c
src/utils/eloop.h
src/utils/eloop_win.c
src/utils/os.h
src/utils/os_internal.c
src/utils/os_none.c
src/utils/os_unix.c
src/utils/os_win32.c
wlantest/Makefile
wpa_supplicant/Makefile
wpa_supplicant/scan.c

index 87ff9b4fefe3bdd4c49608e9bd32b936bfbbdac6..b4704bafa9c071dc6574d44b36f3f976472d4079 100644 (file)
@@ -84,6 +84,14 @@ CONFIG_ELOOP=eloop
 endif
 OBJS += ../src/utils/$(CONFIG_ELOOP).o
 OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+
+ifeq ($(CONFIG_ELOOP), eloop)
+# Using glibc < 2.17 requires -lrt for clock_gettime()
+LIBS += -lrt
+LIBS_c += -lrt
+LIBS_h += -lrt
+endif
+
 OBJS += ../src/utils/common.o
 OBJS += ../src/utils/wpa_debug.o
 OBJS_c += ../src/utils/wpa_debug.o
index 2d6aac7e0bab7e754d6548b223371cac31aa2304..e983edcfb6a6317c68d317ec7583ed125917b603 100644 (file)
@@ -31,7 +31,7 @@ struct eloop_sock {
 
 struct eloop_timeout {
        struct dl_list list;
-       struct os_time time;
+       struct os_reltime time;
        void *eloop_data;
        void *user_data;
        eloop_timeout_handler handler;
@@ -484,7 +484,7 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
        timeout = os_zalloc(sizeof(*timeout));
        if (timeout == NULL)
                return -1;
-       if (os_get_time(&timeout->time) < 0) {
+       if (os_get_reltime(&timeout->time) < 0) {
                os_free(timeout);
                return -1;
        }
@@ -514,7 +514,7 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
 
        /* Maintain timeouts in order of increasing time */
        dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-               if (os_time_before(&timeout->time, &tmp->time)) {
+               if (os_reltime_before(&timeout->time, &tmp->time)) {
                        dl_list_add(tmp->list.prev, &timeout->list);
                        return 0;
                }
@@ -558,13 +558,13 @@ int eloop_cancel_timeout(eloop_timeout_handler handler,
 
 int eloop_cancel_timeout_one(eloop_timeout_handler handler,
                             void *eloop_data, void *user_data,
-                            struct os_time *remaining)
+                            struct os_reltime *remaining)
 {
        struct eloop_timeout *timeout, *prev;
        int removed = 0;
-       struct os_time now;
+       struct os_reltime now;
 
-       os_get_time(&now);
+       os_get_reltime(&now);
        remaining->sec = remaining->usec = 0;
 
        dl_list_for_each_safe(timeout, prev, &eloop.timeout,
@@ -573,8 +573,8 @@ int eloop_cancel_timeout_one(eloop_timeout_handler handler,
                    (timeout->eloop_data == eloop_data) &&
                    (timeout->user_data == user_data)) {
                        removed = 1;
-                       if (os_time_before(&now, &timeout->time))
-                               os_time_sub(&timeout->time, &now, remaining);
+                       if (os_reltime_before(&now, &timeout->time))
+                               os_reltime_sub(&timeout->time, &now, remaining);
                        eloop_remove_timeout(timeout);
                        break;
                }
@@ -603,7 +603,7 @@ int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
                          eloop_timeout_handler handler, void *eloop_data,
                          void *user_data)
 {
-       struct os_time now, requested, remaining;
+       struct os_reltime now, requested, remaining;
        struct eloop_timeout *tmp;
 
        dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
@@ -612,9 +612,9 @@ int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
                    tmp->user_data == user_data) {
                        requested.sec = req_secs;
                        requested.usec = req_usecs;
-                       os_get_time(&now);
-                       os_time_sub(&tmp->time, &now, &remaining);
-                       if (os_time_before(&requested, &remaining)) {
+                       os_get_reltime(&now);
+                       os_reltime_sub(&tmp->time, &now, &remaining);
+                       if (os_reltime_before(&requested, &remaining)) {
                                eloop_cancel_timeout(handler, eloop_data,
                                                     user_data);
                                eloop_register_timeout(requested.sec,
@@ -634,7 +634,7 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
                            eloop_timeout_handler handler, void *eloop_data,
                            void *user_data)
 {
-       struct os_time now, requested, remaining;
+       struct os_reltime now, requested, remaining;
        struct eloop_timeout *tmp;
 
        dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
@@ -643,9 +643,9 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
                    tmp->user_data == user_data) {
                        requested.sec = req_secs;
                        requested.usec = req_usecs;
-                       os_get_time(&now);
-                       os_time_sub(&tmp->time, &now, &remaining);
-                       if (os_time_before(&remaining, &requested)) {
+                       os_get_reltime(&now);
+                       os_reltime_sub(&tmp->time, &now, &remaining);
+                       if (os_reltime_before(&remaining, &requested)) {
                                eloop_cancel_timeout(handler, eloop_data,
                                                     user_data);
                                eloop_register_timeout(requested.sec,
@@ -776,7 +776,7 @@ void eloop_run(void)
        struct timeval _tv;
 #endif /* CONFIG_ELOOP_POLL */
        int res;
-       struct os_time tv, now;
+       struct os_reltime tv, now;
 
 #ifndef CONFIG_ELOOP_POLL
        rfds = os_malloc(sizeof(*rfds));
@@ -793,9 +793,9 @@ void eloop_run(void)
                timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
                                        list);
                if (timeout) {
-                       os_get_time(&now);
-                       if (os_time_before(&now, &timeout->time))
-                               os_time_sub(&timeout->time, &now, &tv);
+                       os_get_reltime(&now);
+                       if (os_reltime_before(&now, &timeout->time))
+                               os_reltime_sub(&timeout->time, &now, &tv);
                        else
                                tv.sec = tv.usec = 0;
 #ifdef CONFIG_ELOOP_POLL
@@ -837,8 +837,8 @@ void eloop_run(void)
                timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
                                        list);
                if (timeout) {
-                       os_get_time(&now);
-                       if (!os_time_before(&now, &timeout->time)) {
+                       os_get_reltime(&now);
+                       if (!os_reltime_before(&now, &timeout->time)) {
                                void *eloop_data = timeout->eloop_data;
                                void *user_data = timeout->user_data;
                                eloop_timeout_handler handler =
@@ -883,9 +883,9 @@ void eloop_terminate(void)
 void eloop_destroy(void)
 {
        struct eloop_timeout *timeout, *prev;
-       struct os_time now;
+       struct os_reltime now;
 
-       os_get_time(&now);
+       os_get_reltime(&now);
        dl_list_for_each_safe(timeout, prev, &eloop.timeout,
                              struct eloop_timeout, list) {
                int sec, usec;
index 274714f88963d96134f95559e8eba81440638ce7..d3980fa4959c6309bb29515a5f6929268aa13a2a 100644 (file)
@@ -207,7 +207,7 @@ int eloop_cancel_timeout(eloop_timeout_handler handler,
  */
 int eloop_cancel_timeout_one(eloop_timeout_handler handler,
                             void *eloop_data, void *user_data,
-                            struct os_time *remaining);
+                            struct os_reltime *remaining);
 
 /**
  * eloop_is_timeout_registered - Check if a timeout is already registered
index e87d82ac97250bec2a9b0b7fba742be1d6e31199..a1f999648f17d27c3589c3d63c30b9a2393bb8d6 100644 (file)
@@ -31,7 +31,7 @@ struct eloop_event {
 
 struct eloop_timeout {
        struct dl_list list;
-       struct os_time time;
+       struct os_reltime time;
        void *eloop_data;
        void *user_data;
        eloop_timeout_handler handler;
@@ -244,7 +244,7 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
        timeout = os_zalloc(sizeof(*timeout));
        if (timeout == NULL)
                return -1;
-       if (os_get_time(&timeout->time) < 0) {
+       if (os_get_reltime(&timeout->time) < 0) {
                os_free(timeout);
                return -1;
        }
@@ -271,7 +271,7 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
 
        /* Maintain timeouts in order of increasing time */
        dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-               if (os_time_before(&timeout->time, &tmp->time)) {
+               if (os_reltime_before(&timeout->time, &tmp->time)) {
                        dl_list_add(tmp->list.prev, &timeout->list);
                        return 0;
                }
@@ -313,13 +313,13 @@ int eloop_cancel_timeout(eloop_timeout_handler handler,
 
 int eloop_cancel_timeout_one(eloop_timeout_handler handler,
                             void *eloop_data, void *user_data,
-                            struct os_time *remaining)
+                            struct os_reltime *remaining)
 {
        struct eloop_timeout *timeout, *prev;
        int removed = 0;
-       struct os_time now;
+       struct os_reltime now;
 
-       os_get_time(&now);
+       os_get_reltime(&now);
        remaining->sec = remaining->usec = 0;
 
        dl_list_for_each_safe(timeout, prev, &eloop.timeout,
@@ -328,8 +328,8 @@ int eloop_cancel_timeout_one(eloop_timeout_handler handler,
                    (timeout->eloop_data == eloop_data) &&
                    (timeout->user_data == user_data)) {
                        removed = 1;
-                       if (os_time_before(&now, &timeout->time))
-                               os_time_sub(&timeout->time, &now, remaining);
+                       if (os_reltime_before(&now, &timeout->time))
+                               os_reltime_sub(&timeout->time, &now, remaining);
                        eloop_remove_timeout(timeout);
                        break;
                }
@@ -358,7 +358,7 @@ int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
                          eloop_timeout_handler handler, void *eloop_data,
                          void *user_data)
 {
-       struct os_time now, requested, remaining;
+       struct os_reltime now, requested, remaining;
        struct eloop_timeout *tmp;
 
        dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
@@ -367,9 +367,9 @@ int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
                    tmp->user_data == user_data) {
                        requested.sec = req_secs;
                        requested.usec = req_usecs;
-                       os_get_time(&now);
-                       os_time_sub(&tmp->time, &now, &remaining);
-                       if (os_time_before(&requested, &remaining)) {
+                       os_get_reltime(&now);
+                       os_reltime_sub(&tmp->time, &now, &remaining);
+                       if (os_reltime_before(&requested, &remaining)) {
                                eloop_cancel_timeout(handler, eloop_data,
                                                     user_data);
                                eloop_register_timeout(requested.sec,
@@ -389,7 +389,7 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
                            eloop_timeout_handler handler, void *eloop_data,
                            void *user_data)
 {
-       struct os_time now, requested, remaining;
+       struct os_reltime now, requested, remaining;
        struct eloop_timeout *tmp;
 
        dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
@@ -398,9 +398,9 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
                    tmp->user_data == user_data) {
                        requested.sec = req_secs;
                        requested.usec = req_usecs;
-                       os_get_time(&now);
-                       os_time_sub(&tmp->time, &now, &remaining);
-                       if (os_time_before(&remaining, &requested)) {
+                       os_get_reltime(&now);
+                       os_reltime_sub(&tmp->time, &now, &remaining);
+                       if (os_reltime_before(&remaining, &requested)) {
                                eloop_cancel_timeout(handler, eloop_data,
                                                     user_data);
                                eloop_register_timeout(requested.sec,
@@ -530,7 +530,7 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler,
 
 void eloop_run(void)
 {
-       struct os_time tv, now;
+       struct os_reltime tv, now;
        DWORD count, ret, timeout_val, err;
        size_t i;
 
@@ -542,9 +542,9 @@ void eloop_run(void)
                timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
                                        list);
                if (timeout) {
-                       os_get_time(&now);
-                       if (os_time_before(&now, &timeout->time))
-                               os_time_sub(&timeout->time, &now, &tv);
+                       os_get_reltime(&now);
+                       if (os_reltime_before(&now, &timeout->time))
+                               os_reltime_sub(&timeout->time, &now, &tv);
                }
 
                count = 0;
@@ -583,8 +583,8 @@ void eloop_run(void)
                timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
                                        list);
                if (timeout) {
-                       os_get_time(&now);
-                       if (!os_time_before(&now, &timeout->time)) {
+                       os_get_reltime(&now);
+                       if (!os_reltime_before(&now, &timeout->time)) {
                                void *eloop_data = timeout->eloop_data;
                                void *user_data = timeout->user_data;
                                eloop_timeout_handler handler =
index 2aab13af09d7722232ef19e384f5e94e289e1ba5..77dc6e38a016c738b17376c8311ccc99a94756fe 100644 (file)
@@ -23,6 +23,11 @@ struct os_time {
        os_time_t usec;
 };
 
+struct os_reltime {
+       os_time_t sec;
+       os_time_t usec;
+};
+
 /**
  * os_get_time - Get current time (sec, usec)
  * @t: Pointer to buffer for the time
@@ -30,21 +35,56 @@ struct os_time {
  */
 int os_get_time(struct os_time *t);
 
+/**
+ * os_get_reltime - Get relative time (sec, usec)
+ * @t: Pointer to buffer for the time
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_reltime(struct os_reltime *t);
+
+
+/* Helpers for handling struct os_time */
+
+static inline int os_time_before(struct os_time *a, struct os_time *b)
+{
+       return (a->sec < b->sec) ||
+              (a->sec == b->sec && a->usec < b->usec);
+}
+
+
+static inline void os_time_sub(struct os_time *a, struct os_time *b,
+                              struct os_time *res)
+{
+       res->sec = a->sec - b->sec;
+       res->usec = a->usec - b->usec;
+       if (res->usec < 0) {
+               res->sec--;
+               res->usec += 1000000;
+       }
+}
+
 
-/* Helper macros for handling struct os_time */
+/* Helpers for handling struct os_reltime */
 
-#define os_time_before(a, b) \
-       ((a)->sec < (b)->sec || \
-        ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+static inline int os_reltime_before(struct os_reltime *a,
+                                   struct os_reltime *b)
+{
+       return (a->sec < b->sec) ||
+              (a->sec == b->sec && a->usec < b->usec);
+}
+
+
+static inline void os_reltime_sub(struct os_reltime *a, struct os_reltime *b,
+                                 struct os_reltime *res)
+{
+       res->sec = a->sec - b->sec;
+       res->usec = a->usec - b->usec;
+       if (res->usec < 0) {
+               res->sec--;
+               res->usec += 1000000;
+       }
+}
 
-#define os_time_sub(a, b, res) do { \
-       (res)->sec = (a)->sec - (b)->sec; \
-       (res)->usec = (a)->usec - (b)->usec; \
-       if ((res)->usec < 0) { \
-               (res)->sec--; \
-               (res)->usec += 1000000; \
-       } \
-} while (0)
 
 /**
  * os_mktime - Convert broken-down time into seconds since 1970-01-01
index e4b7fdb18ad354f810bc2b292e55acdd5ae8e606..2cb0d1262d20121cb1a748cf7ca7f4401b31805e 100644 (file)
@@ -41,6 +41,17 @@ int os_get_time(struct os_time *t)
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+       int res;
+       struct timeval tv;
+       res = gettimeofday(&tv, NULL);
+       t->sec = tv.tv_sec;
+       t->usec = tv.tv_usec;
+       return res;
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
              os_time_t *t)
 {
index cabf73bd87fc653add0a2da46c2274b33224453b..228c4724cdd126975c3fd3ad3711e66328eb7d8b 100644 (file)
@@ -26,6 +26,12 @@ int os_get_time(struct os_time *t)
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+       return -1;
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
              os_time_t *t)
 {
index 960073a50f54d60fa68fb094cb9bdb94645b030d..fa67fdfb6869ec24dcfae8c98631d0e1fdffac00 100644 (file)
@@ -60,6 +60,43 @@ int os_get_time(struct os_time *t)
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+#if defined(CLOCK_BOOTTIME)
+       static clockid_t clock_id = CLOCK_BOOTTIME;
+#elif defined(CLOCK_MONOTONIC)
+       static clockid_t clock_id = CLOCK_MONOTONIC;
+#else
+       static clockid_t clock_id = CLOCK_REALTIME;
+#endif
+       struct timespec ts;
+       int res;
+
+       while (1) {
+               res = clock_gettime(clock_id, &ts);
+               if (res == 0) {
+                       t->sec = ts.tv_sec;
+                       t->usec = ts.tv_nsec / 1000;
+                       return 0;
+               }
+               switch (clock_id) {
+#ifdef CLOCK_BOOTTIME
+               case CLOCK_BOOTTIME:
+                       clock_id = CLOCK_MONOTONIC;
+                       break;
+#endif
+#ifdef CLOCK_MONOTONIC
+               case CLOCK_MONOTONIC:
+                       clock_id = CLOCK_REALTIME;
+                       break;
+#endif
+               case CLOCK_REALTIME:
+                       return -1;
+               }
+       }
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
              os_time_t *t)
 {
index 163cebefce265393423af91070d609522e993629..1cfa7a5f81ab7228d25be0eeacc2ba784eacf792 100644 (file)
@@ -47,6 +47,17 @@ int os_get_time(struct os_time *t)
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+       /* consider using performance counters or so instead */
+       struct os_time now;
+       int res = os_get_time(&now);
+       t->sec = now.sec;
+       t->usec = now.usec;
+       return res;
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
              os_time_t *t)
 {
index a08fd547d7d2ddddf8bbeed5a4a6311061ca72d1..175fb515f5e5c3b2f33d3f3481cd90f4a1192779 100644 (file)
@@ -19,6 +19,8 @@ CFLAGS += -I.
 CFLAGS += -I../src
 CFLAGS += -I../src/utils
 
+# glibc < 2.17 needs -lrt for clock_gettime()
+LIBS += -lrt
 
 ifndef LDO
 LDO=$(CC)
@@ -112,7 +114,7 @@ wlantest: $(OBJS) $(LIBWLANTEST)
        $(LDO) $(LDFLAGS) -o wlantest $(OBJS) -L. -lwlantest $(LIBS)
 
 wlantest_cli: $(OBJS_cli) $(LIBWLANTEST)
-       $(LDO) $(LDFLAGS) -o wlantest_cli $(OBJS_cli) -L. -lwlantest
+       $(LDO) $(LDFLAGS) -o wlantest_cli $(OBJS_cli) -L. -lwlantest $(LIBS)
 
 test_vectors: $(TOBJS) $(LIBWLANTEST)
        $(LDO) $(LDFLAGS) -o test_vectors $(TOBJS) -L. -lwlantest $(LIBS)
index 8dcb71b12cf9d0b53e02b1d5fff201205ea2697a..f6a46d28e680a5366f812871577f6d9bd12db769 100644 (file)
@@ -113,6 +113,13 @@ endif
 OBJS += ../src/utils/$(CONFIG_ELOOP).o
 OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
 
+ifeq ($(CONFIG_ELOOP), eloop)
+# Using glibc < 2.17 requires -lrt for clock_gettime()
+LIBS += -lrt
+LIBS_c += -lrt
+LIBS_p += -lrt
+endif
+
 ifdef CONFIG_ELOOP_POLL
 CFLAGS += -DCONFIG_ELOOP_POLL
 endif
index 7baacaa6f555b1abbb1389ef838c4a97678b4975..625ff2860b09ba5b81c69cdc09877afa37ec68b7 100644 (file)
@@ -884,7 +884,7 @@ scan:
 
 void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
 {
-       struct os_time remaining, new_int;
+       struct os_reltime remaining, new_int;
        int cancelled;
 
        cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL,
@@ -892,7 +892,7 @@ void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
 
        new_int.sec = sec;
        new_int.usec = 0;
-       if (cancelled && os_time_before(&remaining, &new_int)) {
+       if (cancelled && os_reltime_before(&remaining, &new_int)) {
                new_int.sec = remaining.sec;
                new_int.usec = remaining.usec;
        }