about summary refs log tree commit diff
path: root/shared/n-dhcp4/src
diff options
context:
space:
mode:
authorSebastien Bacher <seb128@ubuntu.com>2020-05-19 16:38:36 +0200
committerSebastien Bacher <seb128@ubuntu.com>2020-05-19 17:09:07 +0200
commitccf6dc06bbee82c3d49f451545c5317337e0777e (patch)
treea8fddc8c6e2b3b99bebab1d5bb2a64581eff4bfd /shared/n-dhcp4/src
parentf109e55ef130ce84054d5ba3acf4b71cd8c7564a (diff)
parent7ffed1e6136de75188f10ba8763bcb942f932f8e (diff)
Merge remote-tracking branch 'salsa/debian/master' into ubuntu/master
Diffstat (limited to 'shared/n-dhcp4/src')
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-connection.c29
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-probe.c1
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-client.c56
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-private.h1
4 files changed, 50 insertions, 37 deletions
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-connection.c b/shared/n-dhcp4/src/n-dhcp4-c-connection.c
index a5c8ea66..30514e28 100644
--- a/shared/n-dhcp4/src/n-dhcp4-c-connection.c
+++ b/shared/n-dhcp4/src/n-dhcp4-c-connection.c
@@ -1136,6 +1136,13 @@ int n_dhcp4_c_connection_dispatch_timer(NDhcp4CConnection *connection,
         return 0;
 }
 
+/*
+ * Returns:
+ *  0                     on success
+ *  N_DHCP4_E_MALFORMED   if a malformed packet was received
+ *  N_DHCP4_E_UNEXPECTED  if the packet received contains unexpected data
+ *  N_DHCP4_E_AGAIN       if there was another error (non fatal for the client)
+ */
 int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
                                      NDhcp4Incoming **messagep) {
         _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = NULL;
@@ -1150,10 +1157,11 @@ int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
                                                  connection->scratch_buffer,
                                                  sizeof(connection->scratch_buffer),
                                                  &message);
-                if (r)
+                if (!r)
+                        break;
+                else if (r == N_DHCP4_E_MALFORMED)
                         return r;
-
-                break;
+                return N_DHCP4_E_AGAIN;
         case N_DHCP4_C_CONNECTION_STATE_DRAINING:
                 r = n_dhcp4_c_socket_packet_recv(connection->fd_packet,
                                                  connection->scratch_buffer,
@@ -1161,8 +1169,10 @@ int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
                                                  &message);
                 if (!r)
                         break;
-                else if (r != N_DHCP4_E_AGAIN)
+                else if (r == N_DHCP4_E_MALFORMED)
                         return r;
+                else if (r != N_DHCP4_E_AGAIN)
+                        return N_DHCP4_E_AGAIN;
 
                 /*
                  * The UDP socket is open and the packet socket has been shut down
@@ -1180,18 +1190,21 @@ int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
                                               connection->scratch_buffer,
                                               sizeof(connection->scratch_buffer),
                                               &message);
-                if (r)
+                if (!r)
+                        break;
+                else if (r == N_DHCP4_E_MALFORMED)
                         return r;
-
-                break;
+                return N_DHCP4_E_AGAIN;
         default:
                 abort();
                 return -ENOTRECOVERABLE;
         }
 
         r = n_dhcp4_c_connection_verify_incoming(connection, message, &type);
-        if (r)
+        if (r == N_DHCP4_E_MALFORMED || r == N_DHCP4_E_UNEXPECTED)
                 return r;
+        else if (r != 0)
+                return N_DHCP4_E_AGAIN;
 
         if (type == N_DHCP4_MESSAGE_OFFER || type == N_DHCP4_MESSAGE_ACK) {
                 n_dhcp4_c_log(connection->client_config, LOG_INFO,
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-probe.c b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
index e4477a7c..5e971298 100644
--- a/shared/n-dhcp4/src/n-dhcp4-c-probe.c
+++ b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
@@ -1242,6 +1242,7 @@ int n_dhcp4_client_probe_dispatch_io(NDhcp4ClientProbe *probe, uint32_t events)
                         return 0;
                 }
 
+                abort();
                 return r;
         }
 
diff --git a/shared/n-dhcp4/src/n-dhcp4-client.c b/shared/n-dhcp4/src/n-dhcp4-client.c
index 4fa3d65d..6b015e81 100644
--- a/shared/n-dhcp4/src/n-dhcp4-client.c
+++ b/shared/n-dhcp4/src/n-dhcp4-client.c
@@ -388,14 +388,10 @@ _c_public_ int n_dhcp4_client_new(NDhcp4Client **clientp, NDhcp4ClientConfig *co
                 return -errno;
 
         client->fd_timer = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK);
-        if (client->fd_timer < 0) {
-                if (errno != EINVAL)
-                        return -errno;
+        if (client->fd_timer < 0 && errno == EINVAL)
                 client->fd_timer = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
-                if (client->fd_timer < 0)
-                        return -errno;
-                client->timerfd_is_monotonic = true;
-        }
+        if (client->fd_timer < 0)
+                return -errno;
 
         ev.data.u32 = N_DHCP4_CLIENT_EPOLL_TIMER;
         r = epoll_ctl(client->fd_epoll, EPOLL_CTL_ADD, client->fd_timer, &ev);
@@ -498,41 +494,45 @@ int n_dhcp4_client_raise(NDhcp4Client *client, NDhcp4CEventNode **nodep, unsigne
  * must be called whenever a timeout on @client might have changed.
  */
 void n_dhcp4_client_arm_timer(NDhcp4Client *client) {
-        uint64_t timeout = 0;
+        uint64_t now, offset, timeout = 0;
         int r;
 
         if (client->current_probe)
                 n_dhcp4_client_probe_get_timeout(client->current_probe, &timeout);
 
         if (timeout != client->scheduled_timeout) {
-                uint64_t scheduled_timeout = timeout;
-                int flags = TFD_TIMER_ABSTIME;
-
-                if (   timeout != 0
-                    && client->timerfd_is_monotonic) {
-                        uint64_t now;
-
-                        /* the timerfd ticks with CLOCK_MONOTONIC. Calculate and set the relative
-                         * timeout. */
-                        now = n_dhcp4_gettime(CLOCK_BOOTTIME);
-                        if (timeout <= now)
-                                timeout = 1;
-                        else
-                                timeout = timeout - now;
-                        flags = 0;
-                }
+                /*
+                 * Across our codebase, timeouts are specified as absolute
+                 * timestamps on CLOCK_BOOTTIME. Unfortunately, there are
+                 * systems with CLOCK_BOOTTIME support, but timerfd lacks it
+                 * (in particular RHEL). Therefore, our timerfd might be on
+                 * CLOCK_MONOTONIC.
+                 * To account for this, we always schedule a relative timeout.
+                 * We fetch the current time and then calculate the offset
+                 * which we then schedule as relative timeout on the timerfd.
+                 * This works regardless which clock the timerfd runs on.
+                 * Once we no longer support CLOCK_MONOTONIC as fallback, we
+                 * can simply switch to TFD_TIMER_ABSTIME here and specify
+                 * `timeout` directly as value.
+                 */
+                now = n_dhcp4_gettime(CLOCK_BOOTTIME);
+                if (now >= timeout)
+                        offset = 1; /* 0 would disarm the timerfd */
+                else
+                        offset = timeout - now;
+
                 r = timerfd_settime(client->fd_timer,
-                                    flags,
+                                    0,
                                     &(struct itimerspec){
                                         .it_value = {
-                                                .tv_sec = timeout / UINT64_C(1000000000),
-                                                .tv_nsec = timeout % UINT64_C(1000000000),
+                                                .tv_sec = offset / UINT64_C(1000000000),
+                                                .tv_nsec = offset % UINT64_C(1000000000),
                                         },
                                     },
                                     NULL);
                 c_assert(r >= 0);
 
-                client->scheduled_timeout = scheduled_timeout;
+                client->scheduled_timeout = timeout;
         }
 }
 
diff --git a/shared/n-dhcp4/src/n-dhcp4-private.h b/shared/n-dhcp4/src/n-dhcp4-private.h
index f647cb5e..e285d95d 100644
--- a/shared/n-dhcp4/src/n-dhcp4-private.h
+++ b/shared/n-dhcp4/src/n-dhcp4-private.h
@@ -332,7 +332,6 @@ struct NDhcp4Client {
         uint64_t scheduled_timeout;
 
         bool preempted : 1;
-        bool timerfd_is_monotonic : 1;
 };
 
 #define N_DHCP4_CLIENT_NULL(_x) {                                               \