summary refs log tree commit diff
path: root/shared/n-dhcp4/src
diff options
context:
space:
mode:
Diffstat (limited to 'shared/n-dhcp4/src')
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-connection.c1256
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-lease.c405
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-probe.c1294
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-client.c990
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-incoming.c428
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-outgoing.c373
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-private.h759
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-socket.c661
-rw-r--r--shared/n-dhcp4/src/n-dhcp4.h300
-rw-r--r--shared/n-dhcp4/src/util/packet.c448
-rw-r--r--shared/n-dhcp4/src/util/packet.h61
-rw-r--r--shared/n-dhcp4/src/util/socket.c121
-rw-r--r--shared/n-dhcp4/src/util/socket.h11
13 files changed, 0 insertions, 7107 deletions
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-connection.c b/shared/n-dhcp4/src/n-dhcp4-c-connection.c
deleted file mode 100644
index 31235253..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-c-connection.c
+++ /dev/null
@@ -1,1256 +0,0 @@
-/*
- * DHCPv4 Client Connection
- *
- * XXX
- */
-
-#include <assert.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/socket.h> /* needed by linux/netdevice.h */
-#include <linux/netdevice.h>
-#include <net/if_arp.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include "n-dhcp4-private.h"
-#include "util/packet.h"
-
-/**
- * n_dhcp4_c_connection_init() - initialize client connection
- * @connection:                 connection to operate on
- * @client_config:              client configuration to use
- * @probe_config:               client probe configuration to use
- * @log_queue:                  the log queue for logging events
- * @fd_epoll:                   epoll context to attach to, or -1
- *
- * This initializes a new client connection using the configuration given in
- * @client_config and @probe_config.
- *
- * The client-configuration given as @client_config must survive the lifetime
- * of @connection. It is pinned in the connection and used all over the place.
- * The caller must guarantee that the configuration is not deallocated in the
- * meantime. Same is true for @probe_config.
- *
- * The new connection automatically attaches to the epoll context given as
- * @fd_epoll. The epoll FD is retained in the connection and the caller must
- * guarantee that it lives as long as the connection.
- * The caller is explicitly allowed to pass -1 as @fd_epoll, in which case the
- * connection will initialize correctly, but will not be in a usable state.
- * That is, any call to n_dhcp4_c_connection_listen() will fail, since it will
- * be unable to attach to the epoll context. Such a connection can be used to
- * get a detached object that behaves sound, but provides no runtime.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_c_connection_init(NDhcp4CConnection *connection,
-                              NDhcp4ClientConfig *client_config,
-                              NDhcp4ClientProbeConfig *probe_config,
-                              NDhcp4LogQueue *log_queue,
-                              int fd_epoll) {
-        *connection = (NDhcp4CConnection)N_DHCP4_C_CONNECTION_NULL(*connection);
-        connection->client_config = client_config;
-        connection->probe_config = probe_config;
-        connection->fd_epoll = fd_epoll;
-        connection->log_queue = log_queue;
-
-        /*
-         * We explicitly allow initializing connections with an invalid
-         * epoll-fd. The resulting connection immediately transitions into the
-         * CLOSED state. This allows the caller to create dummy connections
-         * useful to provide asynchronous constructor-feedback in the API.
-         *
-         * The effect of this is as if you immediately call
-         * n_dhcp4_c_connection_close() on the new connection. However, by
-         * directly passing -1 in the constructor, you are guaranteed not even
-         * the constructor can ever mess with your epoll-set.
-         */
-        if (connection->fd_epoll < 0)
-                connection->state = N_DHCP4_C_CONNECTION_STATE_CLOSED;
-
-        return 0;
-}
-
-/**
- * n_dhcp4_c_connection_deinit() - deinitialize client connection
- * @connection:                 connection to operate on
- *
- * This deinitializes a connection that was previously initialized via
- * n_dhcp4_c_connection_init(). It will tear down all allocated state and
- * release it.
- *
- * Once this function returns, @connection is re-initialized to
- * N_DHCP4_C_CONNECTION_NULL. If this function is called on a deinitialized
- * connection, it is a no-op.
- */
-void n_dhcp4_c_connection_deinit(NDhcp4CConnection *connection) {
-        n_dhcp4_c_connection_close(connection);
-        n_dhcp4_outgoing_free(connection->request);
-        *connection = (NDhcp4CConnection)N_DHCP4_C_CONNECTION_NULL(*connection);
-}
-
-static void n_dhcp4_c_connection_outgoing_set_secs(NDhcp4Outgoing *message) {
-        uint64_t secs;
-
-        /*
-         * This function sets the `secs` field for outgoing messages. It
-         * expects the base-time and start-time to be already set by the
-         * caller.
-         * For a given outgoing message, its `secs` field describes the time
-         * (in seconds) between the start of the transaction this message is
-         * part of and the start of the operational process (also called the
-         * base time here).
-         *
-         * The operational process in the DHCP sense describes the entire
-         * process of requesting a lease and acquiring it. That is, it starts
-         * with the caller's intent to request a lease, and it ends when we
-         * got granted a lease. The act of refreshing a lease is, in itself, a
-         * new operational process. The base-time describes the start-time
-         * recorded when such a process as initiated.
-         *
-         * A transaction in the DHCP sense describes a request+reply
-         * combination, in most cases. That is, the time a request is sent is
-         * the start-time of a transaction. In the ideal case, the start-time
-         * of the first transaction in an operational process matches the
-         * base-time. However, transactions are often delayed with a randomized
-         * offset to reduce traffic during network bursts.
-         * In some cases, however, transactions are composed out of multiple
-         * requests+reply combinations. This includes, for instance, the SELECT
-         * message following an OFFER. The specification clearly says that
-         * those must be considered a single transaction and thus share the
-         * transaction start-time.
-         *
-         * The `secs` field, thus, describes how long a client has been busy
-         * requesting a lease. DHCP servers and proxies do use it to prioritize
-         * clients.
-         *
-         * Note: Some DHCP relays reject a `secs` value of 0 (which might look
-         *       like it is uninitialized). Hence, we always clamp the value to
-         *       the range `[1, 65535]`.
-         */
-
-        secs = message->userdata.base_time - message->userdata.start_time;
-        secs /= 1000ULL * 1000ULL * 1000ULL; /* nsecs to secs */
-        secs = C_CLAMP(secs, 1, UINT16_MAX);
-
-        n_dhcp4_outgoing_set_secs(message, secs);
-}
-
-int n_dhcp4_c_connection_listen(NDhcp4CConnection *connection) {
-        _c_cleanup_(c_closep) int fd_packet = -1;
-        int r;
-
-        if (connection->state == N_DHCP4_C_CONNECTION_STATE_PACKET)
-                return 0;
-
-        c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_INIT ||
-                 connection->state == N_DHCP4_C_CONNECTION_STATE_DRAINING ||
-                 connection->state == N_DHCP4_C_CONNECTION_STATE_UDP);
-
-        if (connection->fd_packet >= 0) {
-                epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_packet, NULL);
-                connection->fd_packet = c_close(connection->fd_packet);
-        }
-
-        if (connection->fd_udp >= 0) {
-                epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_udp, NULL);
-                connection->fd_udp = c_close(connection->fd_udp);
-        }
-
-        r = n_dhcp4_c_socket_packet_new(&fd_packet, connection->client_config->ifindex);
-        if (r)
-                return r;
-
-        r = epoll_ctl(connection->fd_epoll,
-                      EPOLL_CTL_ADD,
-                      fd_packet,
-                      &(struct epoll_event){
-                              .events = EPOLLIN,
-                              .data = { .u32 = N_DHCP4_CLIENT_EPOLL_IO },
-                      });
-        if (r < 0)
-                return -errno;
-
-        connection->state = N_DHCP4_C_CONNECTION_STATE_PACKET;
-        connection->fd_packet = fd_packet;
-        fd_packet = -1;
-        return 0;
-}
-
-int n_dhcp4_c_connection_connect(NDhcp4CConnection *connection,
-                                 const struct in_addr *client,
-                                 const struct in_addr *server) {
-        _c_cleanup_(c_closep) int fd_udp = -1;
-        int r;
-
-        c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_PACKET);
-
-        r = n_dhcp4_c_socket_udp_new(&fd_udp,
-                                     connection->client_config->ifindex,
-                                     client,
-                                     server);
-        if (r)
-                return r;
-
-        r = epoll_ctl(connection->fd_epoll,
-                      EPOLL_CTL_ADD,
-                      fd_udp,
-                      &(struct epoll_event){
-                              .events = EPOLLIN,
-                              .data = { .u32 = N_DHCP4_CLIENT_EPOLL_IO },
-                      });
-        if (r < 0)
-                return -errno;
-
-        r = packet_shutdown(connection->fd_packet);
-        if (r < 0) {
-                epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, fd_udp, NULL);
-                return r;
-        }
-
-        connection->state = N_DHCP4_C_CONNECTION_STATE_DRAINING;
-        connection->fd_udp = fd_udp;
-        fd_udp = -1;
-        connection->client_ip = client->s_addr;
-        connection->server_ip = server->s_addr;
-        return 0;
-}
-
-void n_dhcp4_c_connection_close(NDhcp4CConnection *connection) {
-        if (connection->fd_udp >= 0) {
-                epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_udp, NULL);
-                connection->fd_udp = c_close(connection->fd_udp);
-        }
-
-        if (connection->fd_packet >= 0) {
-                epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_packet, NULL);
-                connection->fd_packet = c_close(connection->fd_packet);
-        }
-
-        connection->fd_epoll = -1;
-        connection->state = N_DHCP4_C_CONNECTION_STATE_CLOSED;
-}
-
-static int n_dhcp4_c_connection_verify_incoming(NDhcp4CConnection *connection,
-                                                NDhcp4Incoming *message,
-                                                uint8_t *typep) {
-        NDhcp4Header *header = n_dhcp4_incoming_get_header(message);
-        uint8_t type;
-        uint32_t request_xid;
-        uint8_t *id;
-        size_t n_id;
-        int r;
-
-        r = n_dhcp4_incoming_query_message_type(message, &type);
-        if (r) {
-                if (r == N_DHCP4_E_UNSET)
-                        return N_DHCP4_E_MALFORMED;
-                else
-                        return r;
-        }
-
-        switch (type) {
-        case N_DHCP4_MESSAGE_OFFER:
-        case N_DHCP4_MESSAGE_ACK:
-        case N_DHCP4_MESSAGE_NAK:
-                /*
-                 * Only accept replies if there is a pending request, and it
-                 * has a matching transaction id.
-                 */
-                if (!connection->request)
-                        return N_DHCP4_E_UNEXPECTED;
-
-                n_dhcp4_outgoing_get_xid(connection->request, &request_xid);
-                if (header->xid != request_xid)
-                        return N_DHCP4_E_UNEXPECTED;
-
-                break;
-        case N_DHCP4_MESSAGE_FORCERENEW:
-                /*
-                 * Force renew messages are triggered by a server, and do not
-                 * match a pending request.
-                 */
-                break;
-        default:
-                return N_DHCP4_E_UNEXPECTED;
-        }
-
-        /*
-         * In case our transport makes use of the 'chaddr' field, make sure it
-         * matches exactly our address.
-         */
-        switch (connection->client_config->transport) {
-        case N_DHCP4_TRANSPORT_ETHERNET:
-                c_assert(connection->client_config->n_mac == ETH_ALEN);
-
-                if (header->hlen != ETH_ALEN)
-                        return N_DHCP4_E_UNEXPECTED;
-                if (memcmp(header->chaddr, connection->client_config->mac, ETH_ALEN) != 0)
-                        return N_DHCP4_E_UNEXPECTED;
-
-                break;
-        case N_DHCP4_TRANSPORT_INFINIBAND:
-                if (header->hlen != 0)
-                        return N_DHCP4_E_UNEXPECTED;
-
-                break;
-        }
-
-        /*
-         * If a server passes us back a client ID, it must be the one we
-         * provided. We ignore any packets that have mismatching client-ids.
-         */
-        id = NULL;
-        n_id = 0;
-        r = n_dhcp4_incoming_query(message, N_DHCP4_OPTION_CLIENT_IDENTIFIER, &id, &n_id);
-        if (r) {
-                if (r != N_DHCP4_E_UNSET)
-                        return r;
-        } else {
-                if (n_id != connection->client_config->n_client_id)
-                        return N_DHCP4_E_UNEXPECTED;
-                if (memcmp(id, connection->client_config->client_id, n_id) != 0)
-                        return N_DHCP4_E_UNEXPECTED;
-        }
-
-        *typep = type;
-        return 0;
-}
-
-void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection,
-                                      uint64_t *timeoutp) {
-        uint64_t timeout;
-        size_t n_send;
-
-        if (!connection->request) {
-                *timeoutp = 0;
-                return;
-        }
-
-        switch (connection->request->userdata.type) {
-        case N_DHCP4_C_MESSAGE_DISCOVER:
-        case N_DHCP4_C_MESSAGE_SELECT:
-        case N_DHCP4_C_MESSAGE_INFORM:
-                /*
-                 * Resend with an exponential backoff and a one second random
-                 * slack, from a minimum of two seconds to a maximum of sixty
-                 * four.
-                 *
-                 * Note that the RFC says to start at four rather than two
-                 * seconds, and use [-1,1] slack, rather than [0,1].
-                 */
-                n_send = connection->request->userdata.n_send;
-                if (n_send >= 6)
-                        n_send = 6;
-
-                timeout = connection->request->userdata.send_time + ((1ULL << n_send) * 1000000000ULL) + connection->request->userdata.send_jitter;
-
-                break;
-        case N_DHCP4_C_MESSAGE_REBIND:
-        case N_DHCP4_C_MESSAGE_RENEW:
-        case N_DHCP4_C_MESSAGE_REBOOT:
-                /*
-                 * Resend every sixty seconds with a one second random slack.
-                 *
-                 * Note that the RFC says to do this at most once, but we do
-                 * it until we are cancelled.
-                 */
-                timeout = connection->request->userdata.send_time + (60ULL * 1000000000ULL) + connection->request->userdata.send_jitter;
-
-                break;
-        case N_DHCP4_C_MESSAGE_DECLINE:
-        case N_DHCP4_C_MESSAGE_RELEASE:
-                /* XXX make sure these message types are never pinned? */
-                timeout = 0;
-                break;
-        default:
-                c_assert(0);
-        }
-
-        *timeoutp = timeout;
-}
-
-static int n_dhcp4_c_connection_packet_broadcast(NDhcp4CConnection *connection,
-                                                 NDhcp4Outgoing *message) {
-        int r;
-
-        c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_PACKET);
-
-        r = n_dhcp4_c_socket_packet_send(connection->fd_packet,
-                                         connection->client_config->ifindex,
-                                         connection->client_config->broadcast_mac,
-                                         connection->client_config->n_broadcast_mac,
-                                         message);
-        if (r)
-                return r;
-
-        return 0;
-}
-
-static int n_dhcp4_c_connection_udp_broadcast(NDhcp4CConnection *connection,
-                                              NDhcp4Outgoing *message) {
-        int r;
-
-        c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_DRAINING ||
-               connection->state == N_DHCP4_C_CONNECTION_STATE_UDP);
-
-        r = n_dhcp4_c_socket_udp_broadcast(connection->fd_udp, message);
-        if (r)
-                return r;
-
-        return 0;
-}
-
-static int n_dhcp4_c_connection_udp_send(NDhcp4CConnection *connection,
-                                         NDhcp4Outgoing *message) {
-        int r;
-
-        c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_DRAINING ||
-               connection->state == N_DHCP4_C_CONNECTION_STATE_UDP);
-
-        r = n_dhcp4_c_socket_udp_send(connection->fd_udp, message);
-        if (r)
-                return r;
-
-        return 0;
-}
-
-static void n_dhcp4_c_connection_init_header(NDhcp4CConnection *connection,
-                                             NDhcp4Header *header) {
-        bool broadcast = connection->client_config->request_broadcast;
-
-        header->op = N_DHCP4_OP_BOOTREQUEST;
-
-        switch (connection->client_config->transport) {
-        case N_DHCP4_TRANSPORT_ETHERNET:
-                c_assert(connection->client_config->n_mac == ETH_ALEN);
-
-                header->htype = ARPHRD_ETHER;
-                header->hlen = ETH_ALEN;
-                memcpy(header->chaddr, connection->client_config->mac, ETH_ALEN);
-                break;
-        case N_DHCP4_TRANSPORT_INFINIBAND:
-                header->htype = ARPHRD_INFINIBAND;
-                header->hlen = 0;
-
-                /* infiniband mandates to request broadcasts */
-                broadcast = true;
-                break;
-        default:
-                abort();
-                break;
-        }
-
-        if (connection->client_ip != INADDR_ANY) {
-                header->ciaddr = connection->client_ip;
-        } else {
-                /*
-                 * When the IP stack has not been configured, we may
-                 * not be able to receive unicast packets, depending
-                 * on the hardware. If that is the case we must request
-                 * replies from the server to be broadcast.
-                 *
-                 * Once the IP stack has been configured, receiving
-                 * unicast packets is never a problem, so the broadcast
-                 * flag should not be set.
-                 */
-                if (broadcast)
-                        header->flags |= N_DHCP4_MESSAGE_FLAG_BROADCAST;
-        }
-}
-
-static int n_dhcp4_c_connection_new_message(NDhcp4CConnection *connection,
-                                            NDhcp4Outgoing **messagep,
-                                            uint8_t type) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        NDhcp4Header *header;
-        uint8_t message_type;
-        bool via_packet_socket = false;
-        int r;
-
-        switch (type) {
-        case N_DHCP4_C_MESSAGE_DISCOVER:
-                message_type = N_DHCP4_MESSAGE_DISCOVER;
-                via_packet_socket = true;
-                break;
-        case N_DHCP4_C_MESSAGE_INFORM:
-                message_type = N_DHCP4_MESSAGE_INFORM;
-                break;
-        case N_DHCP4_C_MESSAGE_SELECT:
-                message_type = N_DHCP4_MESSAGE_REQUEST;
-                via_packet_socket = true;
-                break;
-        case N_DHCP4_C_MESSAGE_RENEW:
-                message_type = N_DHCP4_MESSAGE_REQUEST;
-                break;
-        case N_DHCP4_C_MESSAGE_REBIND:
-                message_type = N_DHCP4_MESSAGE_REQUEST;
-                break;
-        case N_DHCP4_C_MESSAGE_REBOOT:
-                message_type = N_DHCP4_MESSAGE_REQUEST;
-                via_packet_socket = true;
-                break;
-        case N_DHCP4_C_MESSAGE_RELEASE:
-                message_type = N_DHCP4_MESSAGE_RELEASE;
-                break;
-        case N_DHCP4_C_MESSAGE_DECLINE:
-                message_type = N_DHCP4_MESSAGE_DECLINE;
-                via_packet_socket = true;
-                break;
-        default:
-                abort();
-                return -ENOTRECOVERABLE;
-        }
-
-        /*
-         * We explicitly pass 0 as maximum message size, which makes
-         * NDhcp4Outgoing use the mandated default value from the spec (see its
-         * implementation). While the transport and like layers might support
-         * bigger MTUs (and we very likely know about them through
-         * n_dhcp4_client_update_mtu()), we cannot assume the target DHCP
-         * server supports parsing packets bigger than the minimum (and it is
-         * allowed to refuse bigger IP packets, even if the network supports
-         * transmission of them).
-         *
-         * We could theoretically increase this for packets other than the
-         * initial discovery. However, clients are unlikely to ever send large
-         * packets, so we just keep the same default for all outgoing packets.
-         */
-        r = n_dhcp4_outgoing_new(&message, 0, N_DHCP4_OVERLOAD_FILE | N_DHCP4_OVERLOAD_SNAME);
-        if (r)
-                return r;
-
-        header = n_dhcp4_outgoing_get_header(message);
-        n_dhcp4_c_connection_init_header(connection, header);
-
-        message->userdata.type = type;
-        message->userdata.message_type = message_type;
-
-        /*
-         * Note that some implementations expect the MESSAGE_TYPE option to be
-         * the first option, and possibly even hard-code access to it. Hence,
-         * we really should make sure to pass it first as well.
-         */
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_MESSAGE_TYPE, &message_type, sizeof(message_type));
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message,
-                                    N_DHCP4_OPTION_CLIENT_IDENTIFIER,
-                                    connection->client_config->client_id,
-                                    connection->client_config->n_client_id);
-        if (r)
-                return r;
-
-        switch (message_type) {
-        case N_DHCP4_MESSAGE_DISCOVER:
-        case N_DHCP4_MESSAGE_REQUEST:
-        case N_DHCP4_MESSAGE_INFORM: {
-                uint16_t mtu;
-
-                if (connection->probe_config->n_request_parameters > 0) {
-                        r = n_dhcp4_outgoing_append(message,
-                                                    N_DHCP4_OPTION_PARAMETER_REQUEST_LIST,
-                                                    connection->probe_config->request_parameters,
-                                                    connection->probe_config->n_request_parameters);
-                        if (r)
-                                return r;
-                }
-
-                if (via_packet_socket) {
-                        /*
-                         * In case of packet sockets, we do not support
-                         * fragmentation. Hence, our maximum message size
-                         * equals the transport MTU. In case no mtu is given,
-                         * we use the minimum size mandated by the IP spec. If
-                         * we omit the field, some implementations will
-                         * interpret this to mean any packet size is supported,
-                         * which we rather not want as default behavior (we can
-                         * always support suppressing this field, if that is
-                         * what the caller wants).
-                         */
-                        mtu = htons(connection->mtu ?: N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE);
-                        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_MAXIMUM_MESSAGE_SIZE, &mtu, sizeof(mtu));
-                        if (r)
-                                return r;
-                } else {
-                        /*
-                         * Once we use UDP sockets, we support fragmentation
-                         * through the kernel IP stack. This means, the biggest
-                         * message we can receive is the maximum UDP size plus
-                         * the possible IP header. This would sum up to
-                         * 2^16-1 + 20 (or even 2^16-1 + 60 if pedantic) and
-                         * thus exceed the option field. Hence, we simply set
-                         * the option to the maximum possible value.
-                         */
-                        mtu = htons(UINT16_MAX);
-                        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_MAXIMUM_MESSAGE_SIZE, &mtu, sizeof(mtu));
-                        if (r)
-                                return r;
-                }
-
-                break;
-        }
-        default:
-                break;
-        }
-
-        *messagep = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 3.1
- *
- *      The client broadcasts a DHCPDISCOVER message on its local physical
- *      subnet.  The DHCPDISCOVER message MAY include options that suggest
- *      values for the network address and lease duration.  BOOTP relay
- *      agents may pass the message on to DHCP servers not on the same
- *      physical subnet.
- *
- *      RFC2131 3.5
- *
- *      [...] in its initial DHCPDISCOVER or DHCPREQUEST message, a client
- *      may provide the server with a list of specific parameters the
- *      client is interested in.  If the client includes a list of
- *      parameters in a DHCPDISCOVER message, it MUST include that list in
- *      any subsequent DHCPREQUEST messages.
- *
- *      [...]
- *
- *      In addition, the client may suggest values for the network address
- *      and lease time in the DHCPDISCOVER message.  The client may include
- *      the 'requested IP address' option to suggest that a particular IP
- *      address be assigned, and may include the 'IP address lease time'
- *      option to suggest the lease time it would like.  Other options
- *      representing "hints" at configuration parameters are allowed in a
- *      DHCPDISCOVER or DHCPREQUEST message.
- *
- *      RFC2131 4.4.1
- *
- *      The client generates and records a random transaction identifier and
- *      inserts that identifier into the 'xid' field.  The client records its
- *      own local time for later use in computing the lease expiration.  The
- *      client then broadcasts the DHCPDISCOVER on the local hardware
- *      broadcast address to the 0xffffffff IP broadcast address and 'DHCP
- *      server' UDP port.
- *
- *      If the 'xid' of an arriving DHCPOFFER message does not match the
- *      'xid' of the most recent DHCPDISCOVER message, the DHCPOFFER message
- *      must be silently discarded.  Any arriving DHCPACK messages must be
- *      silently discarded.
- */
-int n_dhcp4_c_connection_discover_new(NDhcp4CConnection *connection,
-                                      NDhcp4Outgoing **requestp) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_DISCOVER);
-        if (r)
-                return r;
-
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *
- *      RFC2131 4.1.1
- *
- *      The DHCPREQUEST message contains the same 'xid' as the DHCPOFFER
- *      message.
- *
- *      RFC2131 4.3.2
- *
- *      Client inserts the address of the selected server in 'server
- *      identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be
- *      filled in with the yiaddr value from the chosen DHCPOFFER.
- */
-int n_dhcp4_c_connection_select_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **requestp,
-                                    NDhcp4Incoming *offer) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        struct in_addr client;
-        struct in_addr server;
-        uint32_t xid;
-        int r;
-
-        n_dhcp4_incoming_get_yiaddr(offer, &client);
-
-        r = n_dhcp4_incoming_query_server_identifier(offer, &server);
-        if (r)
-                return r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_SELECT);
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_REQUESTED_IP_ADDRESS, &client, sizeof(client));
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_SERVER_IDENTIFIER, &server, sizeof(server));
-        if (r)
-                return r;
-
-        /*
-         * SELECT continues the transaction started by DISCOVER, and as such
-         * keeps the same start time. We also have to preserve the base time
-         * of the selected lease as well as the transaction ID.
-         */
-        message->userdata.start_time = offer->userdata.start_time;
-        message->userdata.base_time = offer->userdata.base_time;
-        message->userdata.client_addr = client.s_addr;
-        n_dhcp4_incoming_get_xid(offer, &xid);
-        n_dhcp4_outgoing_set_xid(message, xid);
-
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 4.3.2
- *
- *      'server identifier' MUST NOT be filled in, 'requested IP address'
- *      option MUST be filled in with client's notion of its previously
- *      assigned address. 'ciaddr' MUST be zero. The client is seeking to
- *      verify a previously allocated, cached configuration. Server SHOULD
- *      send a DHCPNAK message to the client if the 'requested IP address'
- *      is incorrect, or is on the wrong network.
- */
-int n_dhcp4_c_connection_reboot_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **requestp,
-                                    const struct in_addr *client) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_REBOOT);
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_REQUESTED_IP_ADDRESS, client, sizeof(*client));
-        if (r)
-                return r;
-
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 4.3.2
- *
- *      'server identifier' MUST NOT be filled in, 'requested IP address'
- *      option MUST NOT be filled in, 'ciaddr' MUST be filled in with
- *      client's IP address. In this situation, the client is completely
- *      configured, and is trying to extend its lease. This message will
- *      be unicast, so no relay agents will be involved in its
- *      transmission.  Because 'giaddr' is therefore not filled in, the
- *      DHCP server will trust the value in 'ciaddr', and use it when
- *      replying to the client.
- *
- *      A client MAY choose to renew or extend its lease prior to T1.  The
- *      server may choose not to extend the lease (as a policy decision by
- *      the network administrator), but should return a DHCPACK message
- *      regardless.
- *
- *      RFC2131 4.4.5
- *
- *      At time T1 the client moves to RENEWING state and sends (via unicast)
- *      a DHCPREQUEST message to the server to extend its lease.  The client
- *      sets the 'ciaddr' field in the DHCPREQUEST to its current network
- *      address. The client records the local time at which the DHCPREQUEST
- *      message is sent for computation of the lease expiration time.  The
- *      client MUST NOT include a 'server identifier' in the DHCPREQUEST
- *      message.
- */
-int n_dhcp4_c_connection_renew_new(NDhcp4CConnection *connection,
-                                   NDhcp4Outgoing **requestp) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_RENEW);
-        if (r)
-                return r;
-
-        message->userdata.client_addr = connection->client_ip;
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 4.3.2
- *
- *      'server identifier' MUST NOT be filled in, 'requested IP address'
- *      option MUST NOT be filled in, 'ciaddr' MUST be filled in with
- *      client's IP address. In this situation, the client is completely
- *      configured, and is trying to extend its lease. This message MUST
- *      be broadcast to the 0xffffffff IP broadcast address.  The DHCP
- *      server SHOULD check 'ciaddr' for correctness before replying to
- *      the DHCPREQUEST.
- *
- *      RFC2131 4.4.5
- *
- *      If no DHCPACK arrives before time T2, the client moves to REBINDING
- *      state and sends (via broadcast) a DHCPREQUEST message to extend its
- *      lease.  The client sets the 'ciaddr' field in the DHCPREQUEST to its
- *      current network address.  The client MUST NOT include a 'server
- *      identifier' in the DHCPREQUEST message.
- */
-int n_dhcp4_c_connection_rebind_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **requestp) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_REBIND);
-        if (r)
-                return r;
-
-        message->userdata.client_addr = connection->client_ip;
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 3.2
- *
- *      If the client detects that the IP address in the DHCPACK message
- *      is already in use, the client MUST send a DHCPDECLINE message to the
- *      server and restarts the configuration process by requesting a
- *      new network address.
- *
- *      RFC2131 4.4.4
- *
- *      Because the client is declining the use of the IP address supplied by
- *      the server, the client broadcasts DHCPDECLINE messages.
- */
-int n_dhcp4_c_connection_decline_new(NDhcp4CConnection *connection,
-                                     NDhcp4Outgoing **requestp,
-                                     NDhcp4Incoming *ack,
-                                     const char *error) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        struct in_addr client;
-        struct in_addr server;
-        int r;
-
-        n_dhcp4_incoming_get_yiaddr(ack, &client);
-
-        r = n_dhcp4_incoming_query_server_identifier(ack, &server);
-        if (r)
-                return r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_DECLINE);
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_REQUESTED_IP_ADDRESS, &client, sizeof(client));
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_SERVER_IDENTIFIER, &server, sizeof(server));
-        if (r)
-                return r;
-
-        if (error) {
-                r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_ERROR_MESSAGE, error, strlen(error) + 1);
-                if (r)
-                        return r;
-        }
-
-        message->userdata.client_addr = client.s_addr;
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 3.4
- *
- *      If a client has obtained a network address through some other means
- *      (e.g., manual configuration), it may use a DHCPINFORM request message
- *      to obtain other local configuration parameters.
- *
- *      RFC2131 4.4
- *
- *      The DHCPINFORM message is not shown in figure 5.  A client simply
- *      sends the DHCPINFORM and waits for DHCPACK messages.  Once the client
- *      has selected its parameters, it has completed the configuration
- *      process.
- *
- *      RFC2131 4.4.3
- *
- *      The client sends a DHCPINFORM message. The client may request
- *      specific configuration parameters by including the 'parameter request
- *      list' option. The client generates and records a random transaction
- *      identifier and inserts that identifier into the 'xid' field. The
- *      client places its own network address in the 'ciaddr' field. The
- *      client SHOULD NOT request lease time parameters.
- *
- *      The client then unicasts the DHCPINFORM to the DHCP server if it
- *      knows the server's address, otherwise it broadcasts the message to
- *      the limited (all 1s) broadcast address.  DHCPINFORM messages MUST be
- *      directed to the 'DHCP server' UDP port.
- */
-int n_dhcp4_c_connection_inform_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **requestp) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_INFORM);
-        if (r)
-                return r;
-
-        message->userdata.client_addr = connection->client_ip;
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 3.1
- *
- *      The client may choose to relinquish its lease on a network address
- *      by sending a DHCPRELEASE message to the server.  The client
- *      identifies the lease to be released with its 'client identifier',
- *      or 'chaddr' and network address in the DHCPRELEASE message. If the
- *      client used a 'client identifier' when it obtained the lease, it
- *      MUST use the same 'client identifier' in the DHCPRELEASE message.
- *
- *      RFC2131 3.2
- *
- *      The client may choose to relinquish its lease on a network
- *      address by sending a DHCPRELEASE message to the server.  The
- *      client identifies the lease to be released with its
- *      'client identifier', or 'chaddr' and network address in the
- *      DHCPRELEASE message.
- *
- *      Note that in this case, where the client retains its network
- *      address locally, the client will not normally relinquish its
- *      lease during a graceful shutdown.  Only in the case where the
- *      client explicitly needs to relinquish its lease, e.g., the client
- *      is about to be moved to a different subnet, will the client send
- *      a DHCPRELEASE message.
- *
- *      RFC2131 4.4.4
- *
- *      The client unicasts DHCPRELEASE messages to the server.
- *
- *      RFC2131 4.4.6
- *
- *      If the client no longer requires use of its assigned network address
- *      (e.g., the client is gracefully shut down), the client sends a
- *      DHCPRELEASE message to the server.  Note that the correct operation
- *      of DHCP does not depend on the transmission of DHCPRELEASE messages.
- */
-int n_dhcp4_c_connection_release_new(NDhcp4CConnection *connection,
-                                     NDhcp4Outgoing **requestp,
-                                     const char *error) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_RELEASE);
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_SERVER_IDENTIFIER, &connection->server_ip, sizeof(connection->server_ip));
-        if (r)
-                return r;
-
-        if (error) {
-                r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_ERROR_MESSAGE, error, strlen(error) + 1);
-                if (r)
-                        return r;
-        }
-
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-static const char *message_type_to_str(uint8_t type) {
-        switch (type) {
-        case N_DHCP4_MESSAGE_DISCOVER:
-                return "DISCOVER";
-        case N_DHCP4_MESSAGE_OFFER:
-                return "OFFER";
-        case N_DHCP4_MESSAGE_REQUEST:
-                return "REQUEST";
-        case N_DHCP4_MESSAGE_DECLINE:
-                return "DECLINE";
-        case N_DHCP4_MESSAGE_ACK:
-                return "ACK";
-        case N_DHCP4_MESSAGE_NAK:
-                return "NACK";
-        case N_DHCP4_MESSAGE_RELEASE:
-                return "RELEASE";
-        case N_DHCP4_MESSAGE_INFORM:
-                return "INFORM";
-        case N_DHCP4_MESSAGE_FORCERENEW:
-                return "FORCERENEW";
-        default:
-                return "UNKNOWN";
-        }
-}
-
-static int n_dhcp4_c_connection_send_request(NDhcp4CConnection *connection,
-                                             NDhcp4Outgoing *request,
-                                             uint64_t timestamp) {
-        char server_addr[INET_ADDRSTRLEN];
-        char client_addr[INET_ADDRSTRLEN];
-        char error_msg[128];
-        int r;
-        bool broadcast = false;
-
-        /*
-         * Increment the base time and reset the xid field,
-         * where applicable. We never alter the header on
-         * resends of SELECT, as it must always match the
-         * OFFER message they are in reply to.
-         */
-        switch (request->userdata.type) {
-        case N_DHCP4_C_MESSAGE_DISCOVER:
-        case N_DHCP4_C_MESSAGE_INFORM:
-        case N_DHCP4_C_MESSAGE_REBOOT:
-        case N_DHCP4_C_MESSAGE_REBIND:
-        case N_DHCP4_C_MESSAGE_RENEW:
-                request->userdata.base_time = timestamp;
-                n_dhcp4_outgoing_set_xid(request, n_dhcp4_client_probe_config_get_random(connection->probe_config));
-
-                break;
-        case N_DHCP4_C_MESSAGE_SELECT:
-        case N_DHCP4_C_MESSAGE_DECLINE:
-        case N_DHCP4_C_MESSAGE_RELEASE:
-                break;
-        default:
-                c_assert(0);
-        }
-
-        request->userdata.send_time = timestamp;
-        request->userdata.send_jitter = (n_dhcp4_client_probe_config_get_random(connection->probe_config) % 1000000000ULL);
-        n_dhcp4_c_connection_outgoing_set_secs(request);
-
-        switch (request->userdata.type) {
-        case N_DHCP4_C_MESSAGE_DISCOVER:
-        case N_DHCP4_C_MESSAGE_SELECT:
-        case N_DHCP4_C_MESSAGE_REBOOT:
-        case N_DHCP4_C_MESSAGE_DECLINE:
-        case N_DHCP4_C_MESSAGE_REBIND:
-                broadcast = true;
-                r = n_dhcp4_c_connection_packet_broadcast(connection, request);
-                break;
-        case N_DHCP4_C_MESSAGE_INFORM:
-                broadcast = true;
-                r = n_dhcp4_c_connection_udp_broadcast(connection, request);
-                break;
-        case N_DHCP4_C_MESSAGE_RENEW:
-        case N_DHCP4_C_MESSAGE_RELEASE:
-                r = n_dhcp4_c_connection_udp_send(connection, request);
-                break;
-        default:
-                c_assert(0);
-        }
-
-        if (r) {
-                snprintf(error_msg, sizeof(error_msg), ": error %d", r);
-        } else {
-                error_msg[0] = '\0';
-        }
-
-        if (request->userdata.client_addr == INADDR_ANY) {
-                n_dhcp4_log(connection->log_queue,
-                            LOG_INFO,
-                            "send %s to %s%s",
-                            message_type_to_str(request->userdata.message_type),
-                            broadcast ?
-                            "255.255.255.255" :
-                            inet_ntop(AF_INET, &connection->server_ip,
-                                      server_addr, sizeof(server_addr)),
-                            error_msg);
-        } else {
-                n_dhcp4_log(connection->log_queue,
-                            LOG_INFO,
-                            "send %s of %s to %s%s",
-                            message_type_to_str(request->userdata.message_type),
-                            inet_ntop(AF_INET, &request->userdata.client_addr,
-                                      client_addr, sizeof(client_addr)),
-                            broadcast ?
-                            "255.255.255.255" :
-                            inet_ntop(AF_INET, &connection->server_ip,
-                                      server_addr, sizeof(server_addr)),
-                            error_msg);
-        }
-
-        ++request->userdata.n_send;
-        return 0;
-}
-
-int n_dhcp4_c_connection_start_request(NDhcp4CConnection *connection,
-                                       NDhcp4Outgoing *request,
-                                       uint64_t timestamp) {
-        int r;
-
-        /*
-         * This function starts a request, but in the case of SELECT it
-         * continues a previous transaction, so we do not want to reset
-         * the start time. Only set the start time if it was not already
-         * set.
-         */
-        if (request->userdata.start_time == 0)
-                request->userdata.start_time = timestamp;
-
-        connection->request = n_dhcp4_outgoing_free(connection->request);
-
-        r = n_dhcp4_c_connection_send_request(connection, request, timestamp);
-        if (r)
-                return r;
-
-        connection->request = request;
-
-        return 0;
-}
-
-int n_dhcp4_c_connection_dispatch_timer(NDhcp4CConnection *connection,
-                                        uint64_t timestamp) {
-        uint64_t timeout;
-        int r;
-
-        if (!connection->request)
-                return 0;
-
-        n_dhcp4_c_connection_get_timeout(connection, &timeout);
-
-        if (timeout > timestamp)
-                return 0;
-
-        r = n_dhcp4_c_connection_send_request(connection, connection->request, timestamp);
-        if (r)
-                return r;
-
-        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;
-        char serv_addr[INET_ADDRSTRLEN];
-        char client_addr[INET_ADDRSTRLEN];
-        uint8_t type;
-        int r;
-
-        switch (connection->state) {
-        case N_DHCP4_C_CONNECTION_STATE_PACKET:
-                r = n_dhcp4_c_socket_packet_recv(connection->fd_packet,
-                                                 connection->scratch_buffer,
-                                                 sizeof(connection->scratch_buffer),
-                                                 &message);
-                if (!r)
-                        break;
-                else if (r == N_DHCP4_E_MALFORMED)
-                        return r;
-                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,
-                                                 sizeof(connection->scratch_buffer),
-                                                 &message);
-                if (!r)
-                        break;
-                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
-                 * and drained, clean up the packet socket and fall through to
-                 * dispatching the UDP socket.
-                 */
-                r = epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_packet, NULL);
-                c_assert(!r);
-                connection->fd_packet = c_close(connection->fd_packet);
-                connection->state = N_DHCP4_C_CONNECTION_STATE_UDP;
-
-                /* fall-through */
-        case N_DHCP4_C_CONNECTION_STATE_UDP:
-                r = n_dhcp4_c_socket_udp_recv(connection->fd_udp,
-                                              connection->scratch_buffer,
-                                              sizeof(connection->scratch_buffer),
-                                              &message);
-                if (!r)
-                        break;
-                else if (r == N_DHCP4_E_MALFORMED)
-                        return r;
-                return N_DHCP4_E_AGAIN;
-        default:
-                abort();
-                return -ENOTRECOVERABLE;
-        }
-
-        r = n_dhcp4_c_connection_verify_incoming(connection, message, &type);
-        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_log(connection->log_queue,
-                            LOG_INFO,
-                            "received %s of %s from %s",
-                            message_type_to_str(type),
-                            inet_ntop(AF_INET, &message->message.header.yiaddr,
-                                      client_addr, sizeof(client_addr)),
-                            inet_ntop(AF_INET, &message->message.header.siaddr,
-                                      serv_addr, sizeof(serv_addr)));
-        } else {
-                n_dhcp4_log(connection->log_queue,
-                            LOG_INFO,
-                            "received %s from %s",
-                            message_type_to_str(type),
-                            inet_ntop(AF_INET, &message->message.header.siaddr,
-                                      serv_addr, sizeof(serv_addr)));
-        }
-
-        switch (type) {
-        case N_DHCP4_MESSAGE_OFFER:
-        case N_DHCP4_MESSAGE_ACK:
-        case N_DHCP4_MESSAGE_NAK:
-                /*
-                 * Remember the start time of the transaction, and the base
-                 * time of any relative timestamps from the pending request.
-                 * The same time applies to the response, and should be
-                 * copied over.
-                 */
-                message->userdata.start_time = connection->request->userdata.start_time;
-                message->userdata.base_time = connection->request->userdata.base_time;
-
-                if (type != N_DHCP4_MESSAGE_OFFER) {
-                        /*
-                         * We only allow one reply to ACK or NAK, but for OFFER we must
-                         * accept several, so we do not free the pinned request.
-                         */
-                        connection->request = n_dhcp4_outgoing_free(connection->request);
-                }
-
-                break;
-        default:
-                break;
-        }
-
-        *messagep = message;
-        message = NULL;
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-lease.c b/shared/n-dhcp4/src/n-dhcp4-c-lease.c
deleted file mode 100644
index 515814d4..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-c-lease.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * DHCP4 Client Leases
- *
- * This implements the public API wrapping DHCP4 client leases. A lease object
- * consists of the information given to us from the server, together with the
- * timestamp recording the start of the validity of the lease.
- *
- * A probe may yield many OFFERS, each of which contains a lease object. One of
- * these offers may be SELECTED, which implicitly rejects all the others.
- * The server may then ACK or NAK the lease which tells us whether or not we
- * are permitted to start using it. Once an ACK has been received, we can
- * configure the address, and only then can we SELECT the lease. If we
- * determine that the offered lease was not appropriate after all we
- * may DECLINE it instead.
- */
-
-#include <assert.h>
-#include <c-list.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include "n-dhcp4.h"
-#include "n-dhcp4-private.h"
-
-/*
- * Compute the absolute timeouts from an incoming message. A message contains relative timeouts and the userdata
- * of the incoming message is set to the offset we must apply to get the absolute values.
- *
- * The special value UINT64_MAX is returned to indicate no or infinite timeouts. In case the given timeouts
- * are invalid relative to each other, we recompute T1 and/or T2 to take their default values. Later timeouts
- * take predecende above earlier ones (T1 is adjusted if it conflicts with T2, etc).
- */
-static int n_dhcp4_incoming_get_timeouts(NDhcp4Incoming *message, uint64_t *t1p, uint64_t *t2p, uint64_t *lifetimep) {
-        uint64_t lifetime, t2, t1;
-        uint32_t u32;
-        int r;
-
-        r = n_dhcp4_incoming_query_lifetime(message, &u32);
-        if (r == N_DHCP4_E_UNSET) {
-                lifetime = UINT64_MAX;
-        } else if (r) {
-                return r;
-        } else if (u32 == UINT32_MAX) {
-                lifetime = UINT64_MAX;
-        } else {
-                lifetime = u32 * (1000000000ULL);
-        }
-
-        r = n_dhcp4_incoming_query_t2(message, &u32);
-        if (r == N_DHCP4_E_UNSET) {
-                if (lifetime == UINT64_MAX)
-                        t2 = UINT64_MAX;
-                else
-                        t2 = (lifetime * 7) / 8;
-        } else if (r) {
-                return r;
-        } else {
-                if (u32 == UINT32_MAX)
-                        t2 = UINT64_MAX;
-                else
-                        t2 = u32 * (1000000000ULL);
-
-                if (t2 > lifetime)
-                        t2 = (lifetime * 7) / 8;
-        }
-
-        r = n_dhcp4_incoming_query_t1(message, &u32);
-        if (r == N_DHCP4_E_UNSET) {
-                if (t2 == UINT64_MAX)
-                        t1 = UINT64_MAX;
-                else
-                        t1 = (t2 * 4) / 7;
-        } else if (r) {
-                return r;
-        } else {
-                if (u32 == UINT32_MAX)
-                        t1 = UINT64_MAX;
-                else
-                        t1 = u32 * (1000000000ULL);
-
-                if (t1 > t2)
-                        t1 = (t2 * 4) / 7;
-        }
-
-        if (lifetime != UINT64_MAX)
-                lifetime += message->userdata.base_time;
-        if (t2 != UINT64_MAX)
-                t2 += message->userdata.base_time;
-        if (t1 != UINT64_MAX)
-                t1 += message->userdata.base_time;
-
-        *lifetimep = lifetime;
-        *t2p = t2;
-        *t1p = t1;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_lease_new() - allocate new client lease object
- * @leasep:                     output argument for new client lease object
- * @message:                    incoming message representing the lease
- *
- * This creates a new client lease object. Client lease objects are simple
- * wrappers around an incoming message representing a lease.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_client_lease_new(NDhcp4ClientLease **leasep, NDhcp4Incoming *message) {
-        _c_cleanup_(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
-        int r;
-
-        c_assert(leasep);
-
-        lease = malloc(sizeof(*lease));
-        if (!lease)
-                return -ENOMEM;
-
-        *lease = (NDhcp4ClientLease)N_DHCP4_CLIENT_LEASE_NULL(*lease);
-
-        r = n_dhcp4_incoming_get_timeouts(message, &lease->t1, &lease->t2, &lease->lifetime);
-        if (r)
-                return r;
-
-        lease->message = message;
-        *leasep = lease;
-        lease = NULL;
-        return 0;
-}
-
-static void n_dhcp4_client_lease_free(NDhcp4ClientLease *lease) {
-        n_dhcp4_client_lease_unlink(lease);
-        n_dhcp4_incoming_free(lease->message);
-        free(lease);
-}
-
-/**
- * n_dhcp4_client_lease_ref() - reference client lease
- * @lease:                      the client lease object to reference
- *
- * Take a new reference to a client lease.
- *
- * Return: the lease.
- */
-_c_public_ NDhcp4ClientLease *n_dhcp4_client_lease_ref(NDhcp4ClientLease *lease) {
-        if (lease)
-                ++lease->n_refs;
-        return lease;
-}
-
-/**
- * n_dhcp4_client_lease_unref() - dereference client lease
- * @lease:                      the client lease object to dereference
- *
- * Relase a reference to a client lease.
- *
- * Return: NULL.
- */
-_c_public_ NDhcp4ClientLease *n_dhcp4_client_lease_unref(NDhcp4ClientLease *lease) {
-        if (lease && !--lease->n_refs)
-                n_dhcp4_client_lease_free(lease);
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_lease_link() - link lease into probe
- * @lease:                      the lease to operate on
- * @probe:                      the probe to link the lease into
- *
- * Associate a lease with a probe. The lease may not already be linked.
- */
-void n_dhcp4_client_lease_link(NDhcp4ClientLease *lease, NDhcp4ClientProbe *probe) {
-        c_assert(!lease->probe);
-        c_assert(!c_list_is_linked(&lease->probe_link));
-
-        lease->probe = probe;
-        c_list_link_tail(&probe->lease_list, &lease->probe_link);
-}
-
-/**
- * n_dhcp4_client_lease_unlink() - unlinke lease from its probe
- * @lease:                      the lease to operate on
- *
- * Dissassociate a lease from a probe if it is associated with one. Otherwise,
- * this is a noop.
- */
-void n_dhcp4_client_lease_unlink(NDhcp4ClientLease *lease) {
-        lease->probe = NULL;
-        c_list_unlink(&lease->probe_link);
-}
-
-/**
- * n_dhcp4_client_lease_get_yiaddr() - get the IP address
- * @lease:                      the lease to operate on
- * @yiaddr:                     return argument for the IP address
- *
- * Gets the IP address contained in the lease. Or INADDR_ANY if the lease
- * does not contain an IP address.
- */
-_c_public_ void n_dhcp4_client_lease_get_yiaddr(NDhcp4ClientLease *lease, struct in_addr *yiaddr) {
-        NDhcp4Header *header = n_dhcp4_incoming_get_header(lease->message);
-
-        yiaddr->s_addr = header->yiaddr;
-}
-
-/**
- * n_dhcp4_client_lease_get_siaddr() - get the server IP address
- * @lease:                      the lease to operate on
- * @siaddr:                     return argument for the IP address
- *
- * Gets the server IP address contained in the lease. Or INADDR_ANY if the
- * lease does not contain an IP address.
- */
-_c_public_ void n_dhcp4_client_lease_get_siaddr(NDhcp4ClientLease *lease, struct in_addr *siaddr) {
-        NDhcp4Header *header = n_dhcp4_incoming_get_header(lease->message);
-
-        siaddr->s_addr = header->siaddr;
-}
-
-/**
- * n_dhcp4_client_lease_get_basetime() - get the timestamp when the lease was received.
- * @lease:                      the lease to operate on
- * @ns_basetimep:               return argument for the base time in nano seconds
- *
- * Gets the timestamp when the lease was received in CLOCK_BOOTTIME. This
- * is also the base timestamp for the expiration of the lifetime and t1/t2.
- */
-_c_public_ void n_dhcp4_client_lease_get_basetime(NDhcp4ClientLease *lease, uint64_t *ns_basetimep) {
-        *ns_basetimep = lease->message->userdata.base_time;
-}
-
-/**
- * n_dhcp4_client_lease_get_lifetime() - get the lifetime
- * @lease:                      the lease to operate on
- * @ns_lifetimep:               return argument for the lifetime in nano seconds
- *
- * Gets the end of the lease's lifetime in nanoseconds according to CLOCK_BOOTTIME,
- * or (uint64_t)-1 for permanent leases.
- */
-_c_public_ void n_dhcp4_client_lease_get_lifetime(NDhcp4ClientLease *lease, uint64_t *ns_lifetimep) {
-        *ns_lifetimep = lease->lifetime;
-}
-
-/**
- * n_dhcp4_client_lease_get_server_identifier() - get the server identifier
- * @lease:                      the lease to operate on
- * @addr:                       return argument for the server identifier
- *
- * Gets the address contained in the server-identifier DHCP option, in network
- * byte order.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_lease_get_server_identifier (NDhcp4ClientLease *lease, struct in_addr *addr) {
-        uint8_t *data;
-        size_t n_data;
-        int r;
-
-        r = n_dhcp4_incoming_query(lease->message, N_DHCP4_OPTION_SERVER_IDENTIFIER, &data, &n_data);
-        if (r)
-                return r;
-        if (n_data < sizeof(struct in_addr))
-                return N_DHCP4_E_MALFORMED;
-
-        memcpy(addr, data, sizeof(struct in_addr));
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_lease_query() - query the lease for an option
- * @lease:                      the lease to operate on
- * @option:                     the DHCP4 option code
- * @datap:                      return argument of the data pointer
- * @n_datap:                    return argument of data length in bytes
- *
- * Query the lease for a given option. Options internal to the DHCP protocol cannot
- * be queried, and only options that were explicitly requested can be queried.
- *
- * Return: 0 on success,
- *         N_DCHP4_E_INTERNAL if an invalid option is queried,
- *         N_DHCP4_E_UNSET if the lease did not contain the option, or
- *         a negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_lease_query(NDhcp4ClientLease *lease, uint8_t option, uint8_t **datap, size_t *n_datap) {
-        switch (option) {
-        case N_DHCP4_OPTION_PAD:
-        case N_DHCP4_OPTION_REQUESTED_IP_ADDRESS:
-        case N_DHCP4_OPTION_IP_ADDRESS_LEASE_TIME:
-        case N_DHCP4_OPTION_OVERLOAD:
-        case N_DHCP4_OPTION_MESSAGE_TYPE:
-        case N_DHCP4_OPTION_SERVER_IDENTIFIER:
-        case N_DHCP4_OPTION_PARAMETER_REQUEST_LIST:
-        case N_DHCP4_OPTION_ERROR_MESSAGE:
-        case N_DHCP4_OPTION_MAXIMUM_MESSAGE_SIZE:
-        case N_DHCP4_OPTION_RENEWAL_T1_TIME:
-        case N_DHCP4_OPTION_REBINDING_T2_TIME:
-        case N_DHCP4_OPTION_END:
-                return N_DHCP4_E_INTERNAL;
-        }
-
-        /* XXX: refuse to return options that were not requested */
-
-        return n_dhcp4_incoming_query(lease->message, option, datap, n_datap);
-}
-
-/**
- * n_dhcp4_client_lease_select() - select an offered lease
- * @lease:                      lease to operate on
- *
- * Select a lease. This must be a lease that was offered, once
- * one of the leases that were offered in response to a probe was
- * selected none of the others can be.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_lease_select(NDhcp4ClientLease *lease) {
-        NDhcp4ClientLease *l, *t_l;
-        NDhcp4ClientProbe *probe;
-        int r;
-
-        /* XXX error handling, this must be an OFFER */
-
-        if (!lease->probe)
-                return -ENOTRECOVERABLE;
-        if (lease->probe->current_lease)
-                return -ENOTRECOVERABLE;
-
-        r = n_dhcp4_client_probe_transition_select(lease->probe, lease->message, n_dhcp4_gettime(CLOCK_BOOTTIME));
-        if (r)
-                return r;
-
-        /*
-         * Only one of the offered leases can be selected, so flush the list.
-         * All offered lease, including this one are now dead.
-         */
-        probe = lease->probe;
-        c_list_for_each_entry_safe(l, t_l, &probe->lease_list, probe_link)
-                n_dhcp4_client_lease_unlink(l);
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_lease_accept() - accept an ack'ed lease
- * @lease:                      lease to operate on
- *
- * Accept a lease. This must be a lease that was ack'ed by the
- * server.
- *
- * The offered IP address must be fully configured before the lease
- * can be accepted.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_lease_accept(NDhcp4ClientLease *lease) {
-        int r;
-
-        /* XXX error handling, this must be an ACK */
-
-        if (!lease->probe)
-                return -ENOTRECOVERABLE;
-        if (lease->probe->current_lease != lease)
-                return -ENOTRECOVERABLE;
-
-        r = n_dhcp4_client_probe_transition_accept(lease->probe, lease->message);
-        if (r)
-                return r;
-
-        n_dhcp4_client_lease_unlink(lease);
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_lease_decline() - decline an ack'ed lease
- * @lease:                      lease to operate on
- *
- * Decline a lease. This must be a lease that was ack'ed by the
- * server.
- *
- * The offered IP address must not be used once the lease has been
- * decline.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_lease_decline(NDhcp4ClientLease *lease, const char *error) {
-        int r;
-
-        /* XXX: error handling, this must be an ACK */
-
-        if (!lease->probe)
-                return -ENOTRECOVERABLE;
-        if (lease->probe->current_lease != lease)
-                return -ENOTRECOVERABLE;
-
-        r = n_dhcp4_client_probe_transition_decline(lease->probe, lease->message, error, n_dhcp4_gettime(CLOCK_BOOTTIME));
-        if (r)
-                return r;
-
-        lease->probe->current_lease = n_dhcp4_client_lease_unref(lease->probe->current_lease);
-        n_dhcp4_client_lease_unlink(lease);
-
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-probe.c b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
deleted file mode 100644
index 7f20ac05..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-c-probe.c
+++ /dev/null
@@ -1,1294 +0,0 @@
-/*
- * DHCPv4 Client Probes
- *
- * The probe object is used to represent the lifetime of a DHCP client session.
- * A running probe discovers DHCP servers, requests a lease, and maintains that
- * lease.
- */
-
-#include <assert.h>
-#include <c-list.h>
-#include <c-siphash.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/auxv.h>
-#include "n-dhcp4.h"
-#include "n-dhcp4-private.h"
-
-
-static int n_dhcp4_client_probe_option_new(NDhcp4ClientProbeOption **optionp,
-                                    uint8_t option,
-                                    const void *data,
-                                    uint8_t n_data) {
-        NDhcp4ClientProbeOption *op;
-
-        op = malloc(sizeof(*op) + n_data);
-        if (!op)
-                return -ENOMEM;
-
-        op->option = option;
-        op->n_data = n_data;
-        memcpy(op->data, data, n_data);
-
-        *optionp = op;
-        return 0;
-}
-
-static void n_dhcp4_client_probe_option_free(NDhcp4ClientProbeOption *option) {
-        if (option)
-                free(option);
-}
-
-/**
- * n_dhcp4_client_probe_config_new() - create new probe configuration
- * @configp:                    output argument to store new configuration
- *
- * This creates a new probe configuration object. The object is a collection of
- * parameters for probes. No data verification is done by the configuration
- * object. Instead, when passing the configuration to the constructor of a
- * probe, this constructor will perform parameter validation.
- *
- * A probe configuration is an unlinked object only used to pass information to
- * a probe constructor. The caller fully owns the returned configuration object
- * and is responsible to free it when no longer needed.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_probe_config_new(NDhcp4ClientProbeConfig **configp) {
-        _c_cleanup_(n_dhcp4_client_probe_config_freep) NDhcp4ClientProbeConfig *config = NULL;
-
-        config = calloc(1, sizeof(*config));
-        if (!config)
-                return -ENOMEM;
-
-        *config = (NDhcp4ClientProbeConfig)N_DHCP4_CLIENT_PROBE_CONFIG_NULL(*config);
-
-        *configp = config;
-        config = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_config_free() - destroy probe configuration
- * @config:                     configuration to operate on, or NULL
- *
- * This destroys a probe configuration object and deallocates all its
- * resources.
- *
- * If @config is NULL, this is a no-op.
- *
- * Return: NULL is returned.
- */
-_c_public_ NDhcp4ClientProbeConfig *n_dhcp4_client_probe_config_free(NDhcp4ClientProbeConfig *config) {
-        if (!config)
-                return NULL;
-
-        for (unsigned int i = 0; i <= UINT8_MAX; ++i)
-                n_dhcp4_client_probe_option_free(config->options[i]);
-
-        free(config);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_probe_config_dup() - duplicate probe configuration
- * @config:                     configuration to operate on
- * @dupp:                       output argument for duplicate
- *
- * This duplicates the probe configuration given as @config and returns it in
- * @dupp to the caller.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_client_probe_config_dup(NDhcp4ClientProbeConfig *config,
-                                    NDhcp4ClientProbeConfig **dupp) {
-        _c_cleanup_(n_dhcp4_client_probe_config_freep) NDhcp4ClientProbeConfig *dup = NULL;
-        int r;
-
-        r = n_dhcp4_client_probe_config_new(&dup);
-        if (r)
-                return r;
-
-        dup->inform_only = config->inform_only;
-        dup->init_reboot = config->init_reboot;
-        dup->requested_ip = config->requested_ip;
-        dup->ms_start_delay = config->ms_start_delay;
-
-        for (unsigned int i = 0; i < config->n_request_parameters; ++i)
-                dup->request_parameters[dup->n_request_parameters++] = config->request_parameters[i];
-
-        for (unsigned int i = 0; i <= UINT8_MAX; ++i) {
-                if (!config->options[i])
-                        break;
-
-                r = n_dhcp4_client_probe_option_new(&dup->options[i],
-                                                    config->options[i]->option,
-                                                    config->options[i]->data,
-                                                    config->options[i]->n_data);
-                if (r)
-                        return r;
-        }
-
-        *dupp = dup;
-        dup = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_config_set_inform_only() - set inform-only property
- * @config:                     configuration to operate on
- * @inform_only:                value to set
- *
- * This sets the inform-only property of the given configuration object. This
- * property controls whether the client probe should request a full lease, or
- * whether it should just ask for auxiliary information without requesting an
- * address.
- *
- * The default is to request a full lease and address. If inform-only is set to
- * true, only auxiliary information will be requested.
- *
- * XXX: This is currently not implemented, and setting the property has no effect.
- */
-_c_public_ void n_dhcp4_client_probe_config_set_inform_only(NDhcp4ClientProbeConfig *config, bool inform_only) {
-        config->inform_only = inform_only;
-}
-
-/**
- * n_dhcp4_client_probe_config_set_init_reboot() - set init-reboot property
- * @config:                     configuration to operate on
- * @init_reboot:                value to set
- *
- * This sets the init-reboot property of the given configuration object. If this
- * is enabled, a requested IP address must also be set.
- *
- * The default is false. If set to true, a probe will make use of the
- * INIT-REBOOT path, as described by the DHCP specification. In most cases, you
- * do not want this.
- *
- * Background: The INIT-REBOOT path allows a DHCP client to skip
- *             server-discovery when rebooting/resuming their machine. The DHCP
- *             client simply re-requests the lease it had acquired before. This
- *             saves one roundtrip in the success-case, since the DISCOVER step
- *             is skipped. However, there are little to no timeouts involved,
- *             so the roundtrip should be barely noticeable. In contrast, if
- *             the INIT-REBOOT fails (because the lease is no longer valid, or
- *             not valid on this network), the client has to wait for a
- *             possible answer to the request before actually starting the DHCP
- *             process all over. This significantly increases the time needed
- *             to switch networks.
- *             The INIT-REBOOT state might have been a real improvements with
- *             the old resend-timeouts mandated by the DHCP specification.
- *             However, on modern networks with improved timeout values we
- *             recommend against using it.
- */
-_c_public_ void n_dhcp4_client_probe_config_set_init_reboot(NDhcp4ClientProbeConfig *config, bool init_reboot) {
-        config->init_reboot = init_reboot;
-}
-
-/**
- * n_dhcp4_client_probe_config_set_requested_ip() - set requested-ip property
- * @config:                     configuration to operate on
- * @ip:                         value to set
- *
- * This sets the requested-ip property of the given configuration object.
- *
- * The default is all 0. If set to something else, the DHCP discovery will
- * include this IP in its requests to tell DHCP servers which address to pick.
- * Servers are not required to honor this, nor does this have any effect on
- * servers not serving this address.
- *
- * This field should always be set if the caller knows of an address that was
- * previously acquired on this network. It serves as hint to servers and will
- * allow them to provide the same address again.
- */
-_c_public_ void n_dhcp4_client_probe_config_set_requested_ip(NDhcp4ClientProbeConfig *config, struct in_addr ip) {
-        config->requested_ip = ip;
-}
-
-/**
- * n_dhcp4_client_probe_config_set_start_delay() - set start delay
- * @config:                     configuration to operate on
- * @msecs:                      value to set
- *
- * This sets the start delay property of the given configuration object.
- *
- * The default is 9000 ms, which is based on RFC2131. In the RFC the start
- * delay is specified to be a random value in the range 1000 to 10.000 ms.
- * However, there does not appear to be any particular reason to
- * unconditionally wait at least one second, so we move the range down to
- * start at 0 ms. The reason for the random delay is to avoid network-wide
- * events causing too much simultaneous network traffic. However, on modern
- * networks, a more reasonable value may be in the 10 ms range.
- */
-_c_public_ void n_dhcp4_client_probe_config_set_start_delay(NDhcp4ClientProbeConfig *config, uint64_t msecs) {
-        config->ms_start_delay = msecs;
-}
-
-/**
- * n_dhpc4_client_probe_config_request_option() - append option to request from the server
- * @config:                     configuration to operate on
- * @option:                     option to request
- *
- * This adds an option to the list of options to request from the server.
- *
- * A server may send options that we do not request, and it may omit options
- * that we do request. However, to increase the likelyhood of uniform behavior
- * between server implementations, we do not expose options that were not
- * explicitly requested.
- *
- * When called multiple times, the order matters. Earlier requests are
- * considered higher priority than later requests, in case the server must omit
- * some, due to a lack of space. If the same option is requested more than once,
- * only the first call has an effect.
- */
-_c_public_ void n_dhcp4_client_probe_config_request_option(NDhcp4ClientProbeConfig *config, uint8_t option) {
-        for (unsigned int i = 0; i < config->n_request_parameters; ++i) {
-                if (config->request_parameters[i] == option)
-                        return;
-        }
-
-        c_assert(config->n_request_parameters <= UINT8_MAX);
-
-        config->request_parameters[config->n_request_parameters++] = option;
-}
-
-/**
- * n_dhcp4_client_probe_config_append_option() - append option to outgoing messages
- * @config:                     configuration to operate on
- * @option:                     DHCP option number
- * @data:                       payload
- * @n_data:                     number of bytes in payload
- *
- * This sets extra options on a given configuration object.
- *
- * These options are appended verbatim to outgoing messages where
- * that is supported by the specification. The same options are
- * appended to all messages.
- *
- * No option may be appended more than once. Options considered internal
- * to the DHCP protocol may not be appended.
- *
- * Return: 0 on success, N_DHCP4_E_DUPLICATE_OPTION if an option has already been
- *         appended, N_DHCP4_E_INTERNAL if the option is not configurable, or
- *         a negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_probe_config_append_option(NDhcp4ClientProbeConfig *config,
-                                                       uint8_t option,
-                                                       const void *data,
-                                                       uint8_t n_data) {
-        int r;
-
-        /* XXX: filter internal options */
-
-        for (unsigned int i = 0; i <= UINT8_MAX; ++i) {
-                if (config->options[i]) {
-                        if (config->options[i]->option == option)
-                                return N_DHCP4_E_DUPLICATE_OPTION;
-
-                        continue;
-                }
-
-                r = n_dhcp4_client_probe_option_new(&config->options[i],
-                                                    option,
-                                                    data,
-                                                    n_data);
-                if (r)
-                        return r;
-
-                return 0;
-        }
-
-        c_assert(0);
-        return -ENOTRECOVERABLE;
-}
-
-static void n_dhcp4_client_probe_config_initialize_random_seed(NDhcp4ClientProbeConfig *config) {
-        uint8_t hash_seed[] = {
-                0x25, 0x3f, 0x02, 0x75, 0x3a, 0xb8, 0x4f, 0x91,
-                0x9d, 0x0a, 0xd6, 0x15, 0x9d, 0x72, 0x7b, 0xcb,
-        };
-        CSipHash hash = C_SIPHASH_NULL;
-        unsigned short int seed16v[3];
-        const uint8_t *p;
-        uint64_t u64;
-
-        /*
-         * Initialize config's entropy buffer for successive jrand48(3) calls.
-         *
-         * We need random jitter for all timeouts and delays, used to reduce
-         * network traffic during bursts. This is not meant as security measure
-         * but only meant to improve network utilization during bursts. The
-         * random source is thus negligible. However, we want, under all
-         * circumstances, avoid two instances running with the same seed. Thus
-         * we source the seed from AT_RANDOM, which grants us a per-process
-         * unique seed. We then add the current time to make sure consequetive
-         * instances use different seeds (to avoid clashes if processes are
-         * duplicated, or similar), and lastly we add the config memory address
-         * to avoid clashes of multiple parallel instances.
-         *
-         * Again, none of these are meant as security measure, but only to
-         * avoid *ACCIDENTAL* seed clashes. That is, in the case that many
-         * transactions are started in parallel, we delay the individual
-         * messages (as described in the spec), to reduce the traffic on the
-         * network and the chance of packets being dropped (and thus triggering
-         * timeouts and resends).
-         *
-         * We hash everything through SipHash, to avoid exposing AT_RANDOM and
-         * other sources to the network. We use a static salt to distinguish it
-         * from other implementations using the same random source.
-         */
-        c_siphash_init(&hash, hash_seed);
-
-        p = (const uint8_t *)getauxval(AT_RANDOM);
-        if (p)
-                c_siphash_append(&hash, p, 16);
-
-        u64 = n_dhcp4_gettime(CLOCK_MONOTONIC);
-        c_siphash_append(&hash, (const uint8_t *)&u64, sizeof(u64));
-
-        c_siphash_append(&hash, (const uint8_t *)&config, sizeof(config));
-
-        u64 = c_siphash_finalize(&hash);
-
-        seed16v[0] = (u64 >>  0) ^ (u64 >> 48);
-        seed16v[1] = (u64 >> 16) ^ (u64 >>  0);
-        seed16v[2] = (u64 >> 32) ^ (u64 >> 16);
-
-        memcpy(config->entropy, seed16v, sizeof(seed16v));
-}
-
-/**
- * n_dhcp4_client_probe_config_get_random() - get random data
- * @config:                     config object to operate on
- *
- * Fetch the next 32bit random number from the entropy pool in @config.
- * Note that this is in no way suitable for security purposes.
- *
- * Return: the random data.
- */
-uint32_t n_dhcp4_client_probe_config_get_random(NDhcp4ClientProbeConfig *config) {
-        return jrand48(config->entropy);
-};
-
-/**
- * n_dhcp4_client_probe_new() - create new client probe
- * @probep:                     output argument for new client probe
- * @config:                     probe configuration
- * @client:                     client to probe on behalf of
- * @ns_now:                     the current time
- *
- * This creates a new client probe object.
- *
- * If one is already running, the new one will be immediately (but asynchronously)
- * cancelled. Otherwise, a DISCOVER event is scheduled after a randomized delay.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int n_dhcp4_client_probe_new(NDhcp4ClientProbe **probep,
-                             NDhcp4ClientProbeConfig *config,
-                             NDhcp4Client *client,
-                             uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_client_probe_freep) NDhcp4ClientProbe *probe = NULL;
-        bool active;
-        int r;
-
-        /*
-         * If there is already a probe attached, we create the new probe in
-         * detached state. It will not be linked into the epoll context and not
-         * be useful in any way. We immediately raise the CANCELLED event to
-         * notify the caller about it.
-         */
-        active = !client->current_probe;
-
-        probe = calloc(1, sizeof(*probe));
-        if (!probe)
-                return -ENOMEM;
-
-        *probe = (NDhcp4ClientProbe)N_DHCP4_CLIENT_PROBE_NULL(*probe);
-        probe->client = n_dhcp4_client_ref(client);
-
-        r = n_dhcp4_client_probe_config_dup(config, &probe->config);
-        if (r)
-                return r;
-
-        /*
-         * XXX: make seed initialization optional, so the entropy can be reused.
-         */
-        n_dhcp4_client_probe_config_initialize_random_seed(probe->config);
-
-        /* The new probe keeps a reference on @client. So we are sure that &client->log_queue
-         * stays alive as long as we need it. */
-
-        r = n_dhcp4_c_connection_init(&probe->connection,
-                                      client->config,
-                                      probe->config,
-                                      &client->log_queue,
-                                      active ? client->fd_epoll : -1);
-        if (r)
-                return r;
-
-        if (probe->config->requested_ip.s_addr != INADDR_ANY)
-                probe->last_address = probe->config->requested_ip;
-
-        if (probe->config->init_reboot && probe->last_address.s_addr != INADDR_ANY)
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT;
-        else
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
-
-        if (active) {
-                /*
-                 * Defer the sending of DISCOVER by a random amount (by default up to 9 seconds).
-                 */
-                if (probe->state == N_DHCP4_CLIENT_PROBE_STATE_INIT)
-                        probe->ns_deferred = ns_now + (n_dhcp4_client_probe_config_get_random(probe->config) % (probe->config->ms_start_delay * 1000000ULL));
-                probe->client->current_probe = probe;
-        } else {
-                r = n_dhcp4_client_probe_raise(probe,
-                                               NULL,
-                                               N_DHCP4_CLIENT_EVENT_CANCELLED);
-                if (r)
-                        return r;
-        }
-
-        *probep = probe;
-        probe = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_free() - destroy a probe
- * @probe:                      probe to operate on, or NULL
- *
- * This destroys a probe object and deallocates all its resources.
- *
- * If @probe is NULL, this is a no-op.
- *
- * Return: NULL is returned.
- */
-_c_public_ NDhcp4ClientProbe *n_dhcp4_client_probe_free(NDhcp4ClientProbe *probe) {
-        NDhcp4CEventNode *node, *t_node;
-        NDhcp4ClientLease *lease, *t_lease;
-
-        if (!probe)
-                return NULL;
-
-        c_list_for_each_entry_safe(lease, t_lease, &probe->lease_list, probe_link)
-                n_dhcp4_client_lease_unlink(lease);
-
-        c_list_for_each_entry_safe(node, t_node, &probe->event_list, probe_link)
-                n_dhcp4_c_event_node_free(node);
-
-        if (probe == probe->client->current_probe)
-                probe->client->current_probe = NULL;
-
-        n_dhcp4_client_lease_unref(probe->current_lease);
-        n_dhcp4_c_connection_deinit(&probe->connection);
-        n_dhcp4_client_unref(probe->client);
-        n_dhcp4_client_probe_config_free(probe->config);
-
-        c_assert(c_list_is_empty(&probe->lease_list));
-        c_assert(c_list_is_empty(&probe->event_list));
-        free(probe);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_probe_set_userdata() - set userdata pointer
- * @probe:                      the probe to operate on
- * @userdata:                   pointer to userdata
- *
- * Set a userdata pointer. The pointed to data is still owned by the caller, and
- * is completely opaque to the probe.
- */
-_c_public_ void n_dhcp4_client_probe_set_userdata(NDhcp4ClientProbe *probe, void *userdata) {
-        probe->userdata = userdata;
-}
-
-/**
- * n_dhcp4_client_probe_get_userdata() - get userdata pointer
- * @probe:                      the probe to operate on
- * @userdatap:                  return pointer for userdata pointer
- *
- * Get the userdata pointer. The lifetime of the userdata and making sure it is
- * still valid when accessed via the probe is the responsibility of the caller.
- */
-_c_public_ void n_dhcp4_client_probe_get_userdata(NDhcp4ClientProbe *probe, void **userdatap) {
-        *userdatap = probe->userdata;
-}
-
-/**
- * n_dhcp4_client_probe_raise() - XXX
- */
-int n_dhcp4_client_probe_raise(NDhcp4ClientProbe *probe, NDhcp4CEventNode **nodep, unsigned int event) {
-        NDhcp4CEventNode *node;
-        int r;
-
-        r = n_dhcp4_client_raise(probe->client, &node, event);
-        if (r)
-                return r;
-
-        switch (event) {
-        case N_DHCP4_CLIENT_EVENT_OFFER:
-                node->event.offer.probe = probe;
-                break;
-        case N_DHCP4_CLIENT_EVENT_GRANTED:
-                node->event.granted.probe = probe;
-                break;
-        case N_DHCP4_CLIENT_EVENT_RETRACTED:
-                node->event.retracted.probe = probe;
-                break;
-        case N_DHCP4_CLIENT_EVENT_EXTENDED:
-                node->event.extended.probe = probe;
-                break;
-        case N_DHCP4_CLIENT_EVENT_EXPIRED:
-                node->event.expired.probe = probe;
-                break;
-        case N_DHCP4_CLIENT_EVENT_CANCELLED:
-                node->event.cancelled.probe = probe;
-                break;
-        default:
-                c_assert(0);
-                n_dhcp4_c_event_node_free(node);
-                return -ENOTRECOVERABLE;
-        }
-
-        if (nodep)
-                *nodep = node;
-        return 0;
-}
-
-void n_dhcp4_client_probe_get_timeout(NDhcp4ClientProbe *probe, uint64_t *timeoutp) {
-        uint64_t t1 = 0;
-        uint64_t t2 = 0;
-        uint64_t lifetime = 0;
-        uint64_t timeout = 0;
-
-        if (probe->current_lease) {
-                t1 = probe->current_lease->t1;
-                t2 = probe->current_lease->t2;
-                lifetime = probe->current_lease->lifetime;
-        }
-
-        n_dhcp4_c_connection_get_timeout(&probe->connection, &timeout);
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-                /* send DHCP request immediately */
-                timeout = 1;
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-                if (probe->ns_reinit && (!timeout || probe->ns_reinit < timeout))
-                        timeout = probe->ns_reinit;
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-                if (probe->ns_deferred && (!timeout || probe->ns_deferred < timeout))
-                        timeout = probe->ns_deferred;
-
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-                if (t1 && (!timeout || t1 < timeout))
-                        timeout = t1;
-
-                /* fall-through */
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-                if (t2 && (!timeout || t2 < timeout))
-                        timeout = t2;
-
-                /* fall-through */
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-                if (lifetime && (!timeout || lifetime < timeout))
-                        timeout = lifetime;
-                break;
-        default:
-                /* ignore */
-                break;
-        }
-
-        *timeoutp = timeout;
-}
-
-static int n_dhcp4_client_probe_outgoing_append_options(NDhcp4ClientProbe *probe, NDhcp4Outgoing *outgoing) {
-        int r;
-
-        for (unsigned int i = 0; i <= UINT8_MAX; ++i) {
-                if (!probe->config->options[i])
-                        break;
-
-                r = n_dhcp4_outgoing_append(outgoing,
-                                            probe->config->options[i]->option,
-                                            probe->config->options[i]->data,
-                                            probe->config->options[i]->n_data);
-                if (r) {
-                        if (r == N_DHCP4_E_NO_SPACE)
-                                /* XXX */
-                                break;
-
-                        return r;
-                }
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_reboot(NDhcp4ClientProbe *probe, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-                r = n_dhcp4_c_connection_listen(&probe->connection);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_reboot_new(&probe->connection, &request, &probe->last_address);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_REBOOTING;
-                probe->ns_reinit = ns_now + 2000000000ULL;
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                abort();
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-                r = n_dhcp4_c_connection_listen(&probe->connection);
-                if (r)
-                        return r;
-                /* fall-through */
-
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-                r = n_dhcp4_c_connection_discover_new(&probe->connection, &request);
-                if (r)
-                        return r;
-
-                if (probe->last_address.s_addr != INADDR_ANY) {
-                        r = n_dhcp4_outgoing_append_requested_ip(request, probe->last_address);
-                        if (r)
-                                return r;
-                }
-
-                r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_SELECTING;
-                probe->ns_deferred = 0;
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                abort();
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_t1(NDhcp4ClientProbe *probe, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-                r = n_dhcp4_c_connection_renew_new(&probe->connection, &request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_RENEWING;
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                abort();
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_t2(NDhcp4ClientProbe *probe, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-                r = n_dhcp4_c_connection_listen(&probe->connection);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_rebind_new(&probe->connection, &request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_REBINDING;
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                abort();
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_lifetime(NDhcp4ClientProbe *probe) {
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-
-                /* XXX */
-
-                r = n_dhcp4_client_probe_raise(probe,
-                                               NULL,
-                                               N_DHCP4_CLIENT_EVENT_EXPIRED);
-                if (r)
-                        return r;
-
-                c_assert(probe->client->current_probe == probe);
-
-                probe->current_lease = n_dhcp4_client_lease_unref(probe->current_lease);
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
-                probe->ns_deferred =  n_dhcp4_gettime(CLOCK_BOOTTIME) + UINT64_C(1);
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                abort();
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_offer(NDhcp4ClientProbe *probe, NDhcp4Incoming *message_take) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = message_take;
-        _c_cleanup_(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
-        NDhcp4CEventNode *node;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-
-                r = n_dhcp4_client_probe_raise(probe,
-                                               &node,
-                                               N_DHCP4_CLIENT_EVENT_OFFER);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_lease_new(&lease, message);
-                if (r)
-                        return r;
-
-                message = NULL; /* consumed */
-
-                n_dhcp4_client_lease_link(lease, probe);
-
-                node->event.offer.lease = n_dhcp4_client_lease_ref(lease);
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4Incoming *message_take) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = message_take;
-        _c_cleanup_(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
-        NDhcp4CEventNode *node;
-        struct in_addr client = {};
-        struct in_addr server = {};
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-                n_dhcp4_incoming_get_yiaddr(message, &client);
-
-                r = n_dhcp4_incoming_query_server_identifier(message, &server);
-                if (r)
-                        return r;
-                r = n_dhcp4_c_connection_connect(&probe->connection, &client, &server);
-                if (r)
-                        return r;
-                /* fall-through */
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-
-                r = n_dhcp4_client_probe_raise(probe,
-                                               &node,
-                                               N_DHCP4_CLIENT_EVENT_EXTENDED);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_lease_new(&lease, message);
-                if (r)
-                        return r;
-
-                message = NULL; /* consumed */
-
-                n_dhcp4_client_lease_link(lease, probe);
-
-                node->event.extended.lease = n_dhcp4_client_lease_ref(lease);
-                n_dhcp4_client_lease_unref(probe->current_lease);
-                probe->current_lease = n_dhcp4_client_lease_ref(lease);
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_BOUND;
-                n_dhcp4_client_lease_get_yiaddr(lease, &probe->last_address);
-                probe->ns_nak_restart_delay = 0;
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-
-                r = n_dhcp4_client_probe_raise(probe,
-                                               &node,
-                                               N_DHCP4_CLIENT_EVENT_GRANTED);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_lease_new(&lease, message);
-                if (r)
-                        return r;
-
-                message = NULL; /* consumed */
-
-                n_dhcp4_client_lease_link(lease, probe);
-
-                node->event.granted.lease = n_dhcp4_client_lease_ref(lease);
-                probe->current_lease = n_dhcp4_client_lease_ref(lease);
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_GRANTED;
-                probe->ns_nak_restart_delay = 0;
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_nak(NDhcp4ClientProbe *probe) {
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-
-                /* XXX */
-
-                r = n_dhcp4_client_probe_raise(probe,
-                                               NULL,
-                                               N_DHCP4_CLIENT_EVENT_RETRACTED);
-                if (r)
-                        return r;
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
-                probe->ns_deferred = n_dhcp4_gettime(CLOCK_BOOTTIME) + probe->ns_nak_restart_delay;
-                probe->ns_nak_restart_delay = C_CLAMP(probe->ns_nak_restart_delay * 2u,
-                                                      UINT64_C(2)   * UINT64_C(1000000000),
-                                                      UINT64_C(300) * UINT64_C(1000000000));
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-int n_dhcp4_client_probe_transition_select(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-                r = n_dhcp4_c_connection_select_new(&probe->connection, &request, offer);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                /* XXX: ignore other offers */
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_REQUESTING;
-
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_transition_accept() - XXX
- */
-int n_dhcp4_client_probe_transition_accept(NDhcp4ClientProbe *probe, NDhcp4Incoming *ack) {
-        struct in_addr client = {};
-        struct in_addr server = {};
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-                n_dhcp4_incoming_get_yiaddr(ack, &client);
-
-                r = n_dhcp4_incoming_query_server_identifier(ack, &server);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_connect(&probe->connection, &client, &server);
-                if (r)
-                        return r;
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_BOUND;
-
-                n_dhcp4_client_arm_timer(probe->client);
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-/**
- * n_dhc4_client_probe_transition_decline() - XXX
- */
-int n_dhcp4_client_probe_transition_decline(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, const char *error, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-                r = n_dhcp4_c_connection_decline_new(&probe->connection, &request, offer, error);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                /* XXX: what state to transition to? */
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_dispatch_timer() - XXX
- */
-int n_dhcp4_client_probe_dispatch_timer(NDhcp4ClientProbe *probe, uint64_t ns_now) {
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-                r = n_dhcp4_client_probe_transition_reboot(probe, ns_now);
-                if (r)
-                        return r;
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-                if (ns_now >= probe->ns_reinit) {
-                        r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);
-                        if (r)
-                                return r;
-                }
-
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-                if (ns_now >= probe->ns_deferred) {
-                        r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);
-                        if (r)
-                                return r;
-                }
-
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-                if (ns_now >= probe->current_lease->lifetime) {
-                        r = n_dhcp4_client_probe_transition_lifetime(probe);
-                        if (r)
-                                return r;
-                }
-
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-                if (ns_now >= probe->current_lease->lifetime) {
-                        r = n_dhcp4_client_probe_transition_lifetime(probe);
-                        if (r)
-                                return r;
-                } else if (ns_now >= probe->current_lease->t2 &&
-                           probe->state != N_DHCP4_CLIENT_PROBE_STATE_REBINDING) {
-                        r = n_dhcp4_client_probe_transition_t2(probe, ns_now);
-                        if (r)
-                                return r;
-                } else if (ns_now >= probe->current_lease->t1 &&
-                           probe->state == N_DHCP4_CLIENT_PROBE_STATE_BOUND) {
-                        r = n_dhcp4_client_probe_transition_t1(probe, ns_now);
-                        if (r)
-                                return r;
-                }
-                break;
-        default:
-                /* ignore */
-                break;
-        }
-
-        r = n_dhcp4_c_connection_dispatch_timer(&probe->connection, ns_now);
-        if (r)
-                return r;
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_dispatch_connection() - XXX
- */
-int n_dhcp4_client_probe_dispatch_io(NDhcp4ClientProbe *probe, uint32_t events) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = NULL;
-        uint8_t type;
-        int r;
-
-        r = n_dhcp4_c_connection_dispatch_io(&probe->connection, &message);
-        if (r) {
-                if (r == N_DHCP4_E_AGAIN)
-                        return 0;
-                else if (r == N_DHCP4_E_MALFORMED || r == N_DHCP4_E_UNEXPECTED) {
-                        /*
-                         * We fetched something from the sockets, which we
-                         * discarded. We don't know whether there is more data
-                         * to fetch, so we set the preempted flag to notify the
-                         * caller we want to be called again.
-                         */
-                        probe->client->preempted = true;
-                        return 0;
-                }
-
-                abort();
-                return r;
-        }
-
-        /*
-         * We fetched something from the sockets, which we will handle below.
-         * We don't know whether there is more data to fetch, so we set the
-         * preempted flag to notify the caller we want to be called again.
-         */
-        probe->client->preempted = true;
-
-        r = n_dhcp4_incoming_query_message_type(message, &type);
-        if (r == N_DHCP4_E_UNSET || r == N_DHCP4_E_MALFORMED)
-                /*
-                 * XXX: this can never happen as we already queried the message
-                 * type.
-                 */
-                return 0;
-
-        switch (type) {
-        case N_DHCP4_MESSAGE_OFFER:
-                r = n_dhcp4_client_probe_transition_offer(probe, message);
-                message = NULL; /* consumed */
-                if (r)
-                        return r;
-                break;
-        case N_DHCP4_MESSAGE_ACK:
-                r = n_dhcp4_client_probe_transition_ack(probe, message);
-                message = NULL; /* consumed */
-                if (r)
-                        return r;
-                break;
-        case N_DHCP4_MESSAGE_NAK:
-                r = n_dhcp4_client_probe_transition_nak(probe);
-                if (r)
-                        return r;
-                break;
-        default:
-                /*
-                 * We receiveda message type we do not support, simply discard
-                 * it.
-                 */
-                break;
-        }
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_update_mtu() - XXX
- */
-int n_dhcp4_client_probe_update_mtu(NDhcp4ClientProbe *probe, uint16_t mtu) {
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-client.c b/shared/n-dhcp4/src/n-dhcp4-client.c
deleted file mode 100644
index 1dedbf30..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-client.c
+++ /dev/null
@@ -1,990 +0,0 @@
-/*
- * Client Side of the Dynamic Host Configuration Protocol for IPv4
- *
- * This implements the public API around the NDhcp4Client object. The client
- * object is simply a context to track running probes. It manages pending
- * events of all probes, as well as forwards the dispatching requests whenever
- * the dispatcher is run.
- */
-
-#include <assert.h>
-#include <c-list.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <linux/if_ether.h>
-#include <linux/if_infiniband.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/time.h>
-#include <sys/timerfd.h>
-#include <time.h>
-#include <unistd.h>
-#include "n-dhcp4.h"
-#include "n-dhcp4-private.h"
-
-/**
- * n_dhcp4_client_config_new() - allocate new client configuration
- * @configp:                    output argument for new client config
- *
- * This creates a new client configuration object. Client configurations are
- * unlinked objects that merely serve as collection of parameters. They do not
- * perform validity checks.
- *
- * The new client configuration is fully owned by the caller. They are
- * responsible to free the object if no longer needed.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_config_new(NDhcp4ClientConfig **configp) {
-        _c_cleanup_(n_dhcp4_client_config_freep) NDhcp4ClientConfig *config = NULL;
-
-        config = calloc(1, sizeof(*config));
-        if (!config)
-                return -ENOMEM;
-
-        *config = (NDhcp4ClientConfig)N_DHCP4_CLIENT_CONFIG_NULL(*config);
-
-        *configp = config;
-        config = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_config_free() - destroy client configuration
- * @config:                     client configuration to operate on, or NULL
- *
- * This destroys a client configuration and deallocates all its resources. If
- * NULL is passed, this is a no-op.
- *
- * Return: NULL is returned.
- */
-_c_public_ NDhcp4ClientConfig *n_dhcp4_client_config_free(NDhcp4ClientConfig *config) {
-        if (!config)
-                return NULL;
-
-        free(config->client_id);
-        free(config);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_config_dup() - duplicate client configuration
- * @config:                     client configuration to operate on
- * @dupp:                       output argument for duplicate
- *
- * This duplicates the client configuration given as @config and returns it in
- * @dupp to the caller.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_client_config_dup(NDhcp4ClientConfig *config, NDhcp4ClientConfig **dupp) {
-        _c_cleanup_(n_dhcp4_client_config_freep) NDhcp4ClientConfig *dup = NULL;
-        int r;
-
-        r = n_dhcp4_client_config_new(&dup);
-        if (r)
-                return r;
-
-        dup->ifindex = config->ifindex;
-        dup->transport = config->transport;
-        dup->request_broadcast = config->request_broadcast;
-        memcpy(dup->mac, config->mac, sizeof(dup->mac));
-        dup->n_mac = config->n_mac;
-        memcpy(dup->broadcast_mac, config->broadcast_mac, sizeof(dup->broadcast_mac));
-        dup->n_broadcast_mac = config->n_broadcast_mac;
-
-        r = n_dhcp4_client_config_set_client_id(dup,
-                                                config->client_id,
-                                                config->n_client_id);
-        if (r)
-                return r;
-
-        *dupp = dup;
-        dup = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_config_set_ifindex() - set ifindex property
- * @config:                     client configuration to operate on
- * @ifindex:                    ifindex to set
- *
- * This sets the ifindex property of the client configuration. The ifindex
- * specifies the network device that a DHCP client will run on.
- */
-_c_public_ void n_dhcp4_client_config_set_ifindex(NDhcp4ClientConfig *config, int ifindex) {
-        config->ifindex = ifindex;
-}
-
-/**
- * n_dhcp4_client_config_set_transport() - set transport property
- * @config:                     client configuration to operate on
- * @transport:                  transport to set
- *
- * This sets the transport property of the client configuration. The transport
- * defines the hardware transport of the network device that a DHCP client
- * runs on.
- *
- * This takes one of the N_DHCP4_TRANSPORT_* identifiers as argument.
- */
-_c_public_ void n_dhcp4_client_config_set_transport(NDhcp4ClientConfig *config, unsigned int transport) {
-        config->transport = transport;
-}
-
-/**
- * n_dhcp4_client_config_set_request_broadcast() - set request-broadcast property
- * @config:                           configuration to operate on
- * @request_broadcast:                value to set
- *
- * This sets the request_broadcast property of the given configuration object.
- *
- * The default is false. If set to true, a the server will be told to not unicast
- * replies to the client's IP address before it has been configured, but broadcast
- * to INADDR_ANY instead. In most cases, you do not want this.
- *
- * Background: OFFER and ACK messages from DHCP servers to clients are unicast
- *             to the IP address handed out, even before the IP address has
- *             been configured on the target interface. This usually works
- *             because the correct destination hardware address is explicitly
- *             set on the outgoing packets, rather than being resolved (which
- *             would not work). However, some hardware does not accept incoming
- *             IP packets destined for addresses they do not own, even if the
- *             hardware address is correct. In this case, the server must
- *             broadcast the replies in order for the client to receive them.
- *             In general, unnecessary broadcasting is something one wants to
- *             avoid, and some networks will not deliver broadcasts to the
- *             client at all, in which case this flag must not be set.
- */
-_c_public_ void n_dhcp4_client_config_set_request_broadcast(NDhcp4ClientConfig *config, bool request_broadcast) {
-        config->request_broadcast = request_broadcast;
-}
-
-/**
- * n_dhcp4_client_config_set_mac() - set mac property
- * @config:                     client configuration to operate on
- * @mac:                        hardware address to set
- * @n_mac:                      length of the hardware address
- *
- * This sets the mac property of the client configuration. It specifies the
- * hardware address of the local interface that the DHCP client runs on.
- *
- * This function copies the specified hardware address into @config. Any
- * hardware address is supported. It is up to the consumer of the client
- * configuration to verify the validity of the hardware address.
- *
- * Note: This function may truncate the hardware address internally, but
- *       retains the original length. The consumer of this configuration can
- *       thus tell whether the data was truncated and will refuse it.
- *       The internal buffer is big enough to hold any hardware address of all
- *       supported transports. Thus, truncation only happens if you use
- *       unsupported transports, and those will be rejected, anyway.
- */
-_c_public_ void n_dhcp4_client_config_set_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac) {
-        config->n_mac = n_mac;
-
-        if (n_mac > sizeof(config->mac))
-                n_mac = sizeof(config->mac);
-
-        memcpy(config->mac, mac, n_mac);
-}
-
-/**
- * n_dhcp4_client_config_set_broadcast_mac() - set broadcast-mac property
- * @config:                     client configuration to operate on
- * @mac:                        hardware address to set
- * @n_mac:                      length of the hardware address
- *
- * This sets the broadcast-mac property of the client configuration. It
- * specifies the destination hardware address to use for broadcasts on the
- * local interface that the DHCP client runs on.
- *
- * This function copies the specified hardware address into @config. Any
- * hardware address is supported. It is up to the consumer of the client
- * configuration to verify the validity of the hardware address.
- *
- * Note: This function may truncate the hardware address internally, but
- *       retains the original length. The consumer of this configuration can
- *       thus tell whether the data was truncated and will refuse it.
- *       The internal buffer is big enough to hold any hardware address of all
- *       supported transports. Thus, truncation only happens if you use
- *       unsupported transports, and those will be rejected, anyway.
- */
-_c_public_ void n_dhcp4_client_config_set_broadcast_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac) {
-        config->n_broadcast_mac = n_mac;
-
-        if (n_mac > sizeof(config->mac))
-                n_mac = sizeof(config->mac);
-
-        memcpy(config->broadcast_mac, mac, n_mac);
-}
-
-/**
- * n_dhcp4_client_config_set_client_id() - set client-id property
- * @config:                     client configuration to operate on
- * @id:                         client id
- * @n_id:                       length of the client id in bytes. The length
- *                              must be from 2 up to 255 bytes. Set it to 0
- *                              to unset the client-id.
- *
- * This sets the client-id property of @config. It copies the entire client-id
- * buffer into the configuration.
- * See RFC 2132 (section 9.14) for the format of the Client Identifier.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_config_set_client_id(NDhcp4ClientConfig *config, const uint8_t *id, size_t n_id) {
-        uint8_t *t;
-
-        if (n_id == 0) {
-                config->client_id = c_free(config->client_id);
-                config->n_client_id = 0;
-                return 0;
-        }
-
-        if (n_id < 2 || n_id > 255)
-                return -EINVAL;
-
-        t = malloc(n_id + 1);
-        if (!t)
-                return -ENOMEM;
-
-        memcpy(t, id, n_id);
-        t[n_id] = 0; /* safety 0 for debugging */
-
-        free(config->client_id);
-        config->client_id = t;
-        config->n_client_id = n_id;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_set_log_level() - set the logging level of the client
- * @client:                         the client to operate on
- * @level:                          the minimum syslog logging level that is
- *                                  still logged. For example, set to LOG_NOTICE
- *                                  to receive logging events with level LOG_NOTICE
- *                                  and higher. Set to -1 to disable generating
- *                                  logging events (which is also the default).
- *
- * By enabling logging, you can get N_DHCP4_CLIENT_EVENT_LOG events.
- *
- * From the logging event you may steal the message if (and only if) "allow_steal_message"
- * is true. In that case, clear the message field and free the message yourself.
- *
- * If a logging event cannot be logged due to out of memory, one message
- * gets logged that messages are missing. Until the event with that message
- * gets dropped, no further logging events will be queued.
- *
- * You may change the logging level at any time, but it does not affect
- * logging events that are already queued.
-  */
-_c_public_ void n_dhcp4_client_set_log_level(NDhcp4Client *client, int level) {
-        client->log_queue.log_level = level;
-}
-
-/**
- * n_dhcp4_c_event_node_new() - allocate new event
- * @nodep:                      output argument for new event
- *
- * This allocates a new event node and returns it to the caller. The caller
- * fully owns the event-node and is reposonsible to either link it somewhere,
- * or release it.
- *
- * Event nodes can be linked on a client object, as well as optionally on a
- * probe object. As long as an event-node is linked, it will be retrievable by
- * the API user through n_dhcp4_client_pop_event(). Furthermore, destruction of
- * the client, or probe respectively, will clean-up all pending events.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_c_event_node_new(NDhcp4CEventNode **nodep) {
-        NDhcp4CEventNode *node;
-
-        node = calloc(1, sizeof(*node));
-        if (!node)
-                return -ENOMEM;
-
-        *node = (NDhcp4CEventNode)N_DHCP4_C_EVENT_NODE_NULL(*node);
-
-        *nodep = node;
-        return 0;
-}
-
-/**
- * n_dhcp4_c_event_node_free() - deallocate event
- * @node:                       node to operate on, or NULL
- *
- * This deallocates the node given as @node. If the node is linked on a client
- * or probe, it is unlinked automatically.
- *
- * If @probe is NULL, this is a no-op.
- *
- * Return: NULL is returned.
- */
-NDhcp4CEventNode *n_dhcp4_c_event_node_free(NDhcp4CEventNode *node) {
-        if (!node)
-                return NULL;
-
-        switch (node->event.event) {
-        case N_DHCP4_CLIENT_EVENT_OFFER:
-                node->event.offer.lease = n_dhcp4_client_lease_unref(node->event.offer.lease);
-                break;
-        case N_DHCP4_CLIENT_EVENT_GRANTED:
-                node->event.granted.lease = n_dhcp4_client_lease_unref(node->event.granted.lease);
-                break;
-        case N_DHCP4_CLIENT_EVENT_EXTENDED:
-                node->event.extended.lease = n_dhcp4_client_lease_unref(node->event.extended.lease);
-                break;
-        case N_DHCP4_CLIENT_EVENT_LOG:
-                if (_c_unlikely_(!node->event.log.allow_steal_message)) {
-                        /* @node is the static node "nomem_node". It must not be
-                         * freed. */
-                        c_list_unlink(&node->client_link);
-                        node->is_public = false;
-                        return NULL;
-                }
-                node->event.log.message = c_free((char *)node->event.log.message);
-                break;
-        default:
-                break;
-        }
-
-        c_list_unlink(&node->probe_link);
-        c_list_unlink(&node->client_link);
-        free(node);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_new() - allocate new client
- * @clientp:                    output argument for new client
- * @config:                     configuration to use
- *
- * This allocates a new DHCP4 client object and returns it in @clientp to the
- * caller. The caller then owns a single ref-count to the object and is
- * responsible to drop it, when no longer needed.
- *
- * The configuration given as @config is used to initialize the client. The
- * caller is free to destroy the configuration once this function returns.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_new(NDhcp4Client **clientp, NDhcp4ClientConfig *config) {
-        _c_cleanup_(n_dhcp4_client_unrefp) NDhcp4Client *client = NULL;
-        struct epoll_event ev = {
-                .events = EPOLLIN,
-        };
-        int r;
-
-        c_assert(clientp);
-
-        /* verify configuration */
-        {
-                if (config->ifindex < 1)
-                        return N_DHCP4_E_INVALID_IFINDEX;
-
-                switch (config->transport) {
-                case N_DHCP4_TRANSPORT_ETHERNET:
-                        if (config->n_mac != ETH_ALEN ||
-                            config->n_broadcast_mac != ETH_ALEN)
-                                return N_DHCP4_E_INVALID_ADDRESS;
-
-                        break;
-                case N_DHCP4_TRANSPORT_INFINIBAND:
-                        if (config->n_mac != INFINIBAND_ALEN ||
-                            config->n_broadcast_mac != INFINIBAND_ALEN)
-                                return N_DHCP4_E_INVALID_ADDRESS;
-
-                        break;
-                default:
-                        return N_DHCP4_E_INVALID_TRANSPORT;
-                }
-
-                if (config->n_client_id < 1)
-                        return N_DHCP4_E_INVALID_CLIENT_ID;
-        }
-
-        client = malloc(sizeof(*client));
-        if (!client)
-                return -ENOMEM;
-
-        *client = (NDhcp4Client)N_DHCP4_CLIENT_NULL(*client);
-
-        r = n_dhcp4_client_config_dup(config, &client->config);
-        if (r)
-                return r;
-
-        client->fd_epoll = epoll_create1(EPOLL_CLOEXEC);
-        if (client->fd_epoll < 0)
-                return -errno;
-
-        client->fd_timer = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK);
-        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;
-
-        ev.data.u32 = N_DHCP4_CLIENT_EPOLL_TIMER;
-        r = epoll_ctl(client->fd_epoll, EPOLL_CTL_ADD, client->fd_timer, &ev);
-        if (r < 0) {
-                close(client->fd_timer);
-                client->fd_timer = -1;
-                return -errno;
-        }
-
-        *clientp = client;
-        client = NULL;
-        return 0;
-}
-
-static void n_dhcp4_client_free(NDhcp4Client *client) {
-        NDhcp4CEventNode *node, *t_node;
-
-        c_assert(!client->current_probe);
-
-        c_list_for_each_entry_safe(node, t_node, &client->event_list, client_link)
-                n_dhcp4_c_event_node_free(node);
-
-        if (client->fd_timer >= 0) {
-                epoll_ctl(client->fd_epoll, EPOLL_CTL_DEL, client->fd_timer, NULL);
-                close(client->fd_timer);
-        }
-
-        if (client->fd_epoll >= 0)
-                close(client->fd_epoll);
-
-        n_dhcp4_client_config_free(client->config);
-        free(client);
-}
-
-/**
- * n_dhcp4_client_ref() - acquire client reference
- * @client:                     client to operate on, or NULL
- *
- * This acquires a reference to the client given as @client. If @client is
- * NULL, this function is a no-op.
- *
- * Return: @client is returned.
- */
-_c_public_ NDhcp4Client *n_dhcp4_client_ref(NDhcp4Client *client) {
-        if (client)
-                ++client->n_refs;
-        return client;
-}
-
-/**
- * n_dhcp4_client_unref() - release client reference
- * @client:                     client to operate on, or NULL
- *
- * This releases a reference to the client given as @client. If @client is
- * NULL, this is a no-op.
- *
- * Once the last reference is dropped, the client object will get destroyed and
- * deallocated.
- *
- * Return: NULL is returned.
- */
-_c_public_ NDhcp4Client *n_dhcp4_client_unref(NDhcp4Client *client) {
-        if (client && !--client->n_refs)
-                n_dhcp4_client_free(client);
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_raise() - raise event
- * @client:                     client to operate on
- * @nodep:                      output argument for new event, or NULL
- * @event:                      event type to use
- *
- * This creates a new event-node on @client, setting the event-type to @event.
- * The newly created event-node is returned to the caller in @nodep (unless
- * @nodep is NULL).
- *
- * The event-node is automatically linked on @client.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_client_raise(NDhcp4Client *client, NDhcp4CEventNode **nodep, unsigned int event) {
-        NDhcp4CEventNode *node;
-        int r;
-
-        r = n_dhcp4_c_event_node_new(&node);
-        if (r)
-                return r;
-
-        node->event.event = event;
-        c_list_link_tail(&client->event_list, &node->client_link);
-
-        if (nodep)
-                *nodep = node;
-        return 0;
-}
-
-/**
- * n_dhcp4_log_queue_fmt() - add a logging event.
- * @client:                  the NDhcp4LogQueue to operate on
- * @level:                   the syslog logging level
- * @fmt:                     the format string for the message
- * @...                      printf arguments for logging
- *
- * Appends a logging event to the event queue if logging is
- * enabled and the logging level sufficiently high.
- *
- * Queuing a logging event might fail with out of memory.
- * In that case, a static event will be queued that informs
- * about lost messages.
- */
-void n_dhcp4_log_queue_fmt(NDhcp4LogQueue *log_queue,
-                           int level,
-                           const char *fmt,
-                           ...) {
-        NDhcp4CEventNode *node;
-        char *message;
-        va_list ap;
-        int r;
-
-        if (level > log_queue->log_level)
-                return;
-
-        /* Currently, the logging queue is only implemented for
-         * the client. Nobody would enable logging except a
-         * client instance. */
-        c_assert(log_queue->is_client);
-
-        if (!c_list_is_empty (&log_queue->nomem_node.client_link)) {
-                /* we have the nomem_node queued after a recent out
-                 * of memory. This disables all logging messages until
-                 * the event gets popped.
-                 *
-                 * The reason is that we can only queue the nomem_node once,
-                 * so if we now try to append another event and succeed, the
-                 * user wouldn't know which messages got dropped. Instead,
-                 * just drop them all!! */
-                return;
-        }
-
-        r = n_dhcp4_c_event_node_new(&node);
-        if (r < 0)
-                goto handle_nomem;
-
-        va_start(ap, fmt);
-        r = vasprintf(&message, fmt, ap);
-        va_end(ap);
-
-        if (r < 0) {
-                n_dhcp4_c_event_node_free(node);
-                goto handle_nomem;
-        }
-
-        node->event = (NDhcp4ClientEvent) {
-                .event = N_DHCP4_CLIENT_EVENT_LOG,
-                .log = {
-                        .level = level,
-                        .message = message,
-                        .allow_steal_message = true,
-                },
-        };
-
-        c_list_link_tail(log_queue->event_list, &node->client_link);
-        return;
-
-handle_nomem:
-        c_list_link_tail(log_queue->event_list, &log_queue->nomem_node.client_link);
-}
-
-/**
- * n_dhcp4_client_arm_timer() - update timer
- * @client:                     client to operate on
- *
- * This updates the timer on @client to fire on the next pending timeout. This
- * must be called whenever a timeout on @client might have changed.
- */
-void n_dhcp4_client_arm_timer(NDhcp4Client *client) {
-        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) {
-                /*
-                 * 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,
-                                    0,
-                                    &(struct itimerspec){
-                                        .it_value = {
-                                                .tv_sec = offset / UINT64_C(1000000000),
-                                                .tv_nsec = offset % UINT64_C(1000000000),
-                                        },
-                                    },
-                                    NULL);
-                c_assert(r >= 0);
-
-                client->scheduled_timeout = timeout;
-        }
-}
-
-/**
- * n_dhcp4_client_get_fd() - retrieve event FD
- * @client:                     client to operate on
- * @fdp:                        output argument to store FD
- *
- * This retrieves the FD used by the client object given as @client. The FD is
- * always valid, and returned in @fdp.
- *
- * The caller is expected to poll this FD for readable events and call
- * n_dhcp4_client_dispatch() whenever the FD is readable.
- */
-_c_public_ void n_dhcp4_client_get_fd(NDhcp4Client *client, int *fdp) {
-        *fdp = client->fd_epoll;
-}
-
-static int n_dhcp4_client_dispatch_timer(NDhcp4Client *client, struct epoll_event *event) {
-        uint64_t v, ns_now;
-        int r;
-
-        if (event->events & (EPOLLHUP | EPOLLERR)) {
-                /*
-                 * There is no way to handle either gracefully. If we ignored
-                 * them, we would busy-loop, so lets rather forward the error
-                 * to the caller.
-                 */
-                return -ENOTRECOVERABLE;
-        }
-
-        if (event->events & EPOLLIN) {
-                r = read(client->fd_timer, &v, sizeof(v));
-                if (r < 0) {
-                        if (errno == EAGAIN) {
-                                /*
-                                 * There are no more pending events, so nothing
-                                 * to be done. Return to the caller.
-                                 */
-                                return 0;
-                        }
-
-                        /*
-                         * Something failed. We use CLOCK_BOOTTIME/MONOTONIC,
-                         * so ECANCELED cannot happen. Hence, there is no error
-                         * that we could gracefully handle. Fail hard and let
-                         * the caller deal with it.
-                         */
-                        return -errno;
-                } else if (r != sizeof(v) || v == 0) {
-                        /*
-                         * Kernel guarantees 8-byte reads, and only to return
-                         * data if at least one timer triggered; fail hard if
-                         * it suddenly starts exposing unexpected behavior.
-                         */
-                        return -ENOTRECOVERABLE;
-                }
-
-                /*
-                 * Forward the timer-event to the active probe. Timers should
-                 * not fire if there is no probe running, but lets ignore them
-                 * for now, so probe-internals are not leaked to this generic
-                 * client dispatcher.
-                 */
-                if (client->current_probe) {
-                        /*
-                         * Read the current time *after* dispatching the timer,
-                         * to make sure we do not miss wakeups.
-                         */
-                        ns_now = n_dhcp4_gettime(CLOCK_BOOTTIME);
-
-                        r = n_dhcp4_client_probe_dispatch_timer(client->current_probe,
-                                                                ns_now);
-                        if (r)
-                                return r;
-                }
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_dispatch_io(NDhcp4Client *client, struct epoll_event *event) {
-        int r;
-
-        if (client->current_probe)
-                r = n_dhcp4_client_probe_dispatch_io(client->current_probe,
-                                                     event->events);
-        else
-                return -ENOTRECOVERABLE;
-
-        return r;
-}
-
-/**
- * n_dhcp4_client_dispatch() - dispatch client
- * @client:                     client to operate on
- *
- * This dispatches pending operations on @client. It will read incoming
- * messages, write pending data, and handle any timeouts.
- *
- * This function never blocks.
- *
- * If there are more events to dispatch, than would be reasonable to do in a
- * single dispatch, this will return N_DHCP4_E_PREEMPTED. In this case the
- * caller is expected to call into this function again when it is ready to
- * dispatch more events.
- * If your event loop is level-triggered (it very likely is), you can
- * optionally ignore this return code and treat it as success.
- *
- * Return: 0 on success, negative error code on failure, N_DHCP4_E_PREEMPTED if
- *         there is more data to dispatch.
- */
-_c_public_ int n_dhcp4_client_dispatch(NDhcp4Client *client) {
-        struct epoll_event events[2];
-        int n, i, r = 0;
-
-        n = epoll_wait(client->fd_epoll, events, sizeof(events) / sizeof(*events), 0);
-        if (n < 0) {
-                /* Linux never returns EINTR if `timeout == 0'. */
-                return -errno;
-        }
-
-        client->preempted = false;
-
-        for (i = 0; i < n; ++i) {
-                switch (events[i].data.u32) {
-                case N_DHCP4_CLIENT_EPOLL_TIMER:
-                        r = n_dhcp4_client_dispatch_timer(client, events + i);
-                        break;
-                case N_DHCP4_CLIENT_EPOLL_IO:
-                        r = n_dhcp4_client_dispatch_io(client, events + i);
-                        break;
-                default:
-                        c_assert(0);
-                        r = 0;
-                        break;
-                }
-
-                if (r) {
-                        if (r == N_DHCP4_E_DOWN) {
-                                r = n_dhcp4_client_raise(client,
-                                                         NULL,
-                                                         N_DHCP4_CLIENT_EVENT_DOWN);
-                                if (r)
-                                        return r;
-
-                                /* continue normally */
-                        } else if (r) {
-                                if (r >= _N_DHCP4_E_INTERNAL) {
-                                        n_dhcp4_log(&client->log_queue,
-                                                    LOG_ERR,
-                                                    "invalid internal error code %d after dispatch",
-                                                    r);
-                                        return N_DHCP4_E_INTERNAL;
-                                }
-                                return r;
-                        }
-                }
-        }
-
-        n_dhcp4_client_arm_timer(client);
-
-        return client->preempted ? N_DHCP4_E_PREEMPTED : 0;
-}
-
-/**
- * n_dhcp4_client_pop_event() - fetch pending event
- * @client:                     client to operate on
- * @eventp:                     output argument to store next event
- *
- * This fetches the next pending event from the event-queue and returns it to a
- * caller. A pointer to the event is stored in @eventp. If there is no more
- * event queued, NULL is returned.
- *
- * If a valid event is returned, it is accessible until the next call to this
- * function, or the destruction of the context object (this might be either the
- * client object or the probe object, pointed to by the event), whichever
- * happens first.
- * That is, the caller should not pin the returned event object, but copy
- * required information into their own state tracking contexts.
- *
- * The possible events are:
- * * N_DHCP4_CLIENT_EVENT_OFFER:     A lease offered from a server in response
- *                                   to a probe. Several such offers may be
- *                                   received until one of them is selected by
- *                                   the caller. Only one lease may be selected.
- *                                   The attached lease object may be queried
- *                                   for information in order to decide which
- *                                   lease to select, though the information is
- *                                   not guaranteed to stay the same in the
- *                                   final lease.
- * * N_DHCP4_CLIENT_EVENT_GRANTED:   A selected lease was granted by the server.
- *                                   The information in the attached lease
- *                                   object should be used to configure the
- *                                   client. Once the client has been
- *                                   configured, the lease should be accepted.
- * * N_DHCP4_CLIENT_EVENT_RETRACTED: A selected lease offer was retracted by the
- *                                   server. This can happen in case the server
- *                                   offers the same lease to several clients,
- *                                   or the server discovers that the IP address
- *                                   in the lease is already in use.
- * * N_DHCP4_CLIENT_EVENT_EXTENDED:  An active lease is extended, if applicable
- *                                   the kernel should be updated with the new
- *                                   lifetime information for addresses and/or
- *                                   routes.
- * * N_DHCP4_CLIENT_EVENT_EXPIRED:   An active lease failed to be extended by
- *                                   the end of its lifetime. The client should
- *                                   immediately stop using the information
- *                                   contained in the lease.
- * * N_DHCP4_CLIENT_EVENT_DOWN:      The network interface was put down down.
- *                                   The user is recommended to reestablish the
- *                                   lease at the first opportunity when the
- *                                   network comes back up. Note that this is
- *                                   purely informational, the probe will keep
- *                                   running, and if the network topology does
- *                                   not change any lease we have will still be
- *                                   valid.
- * * N_DHCP4_CLIENT_EVENT_CANCELLED: The probe was cancelled. This can happen if
- *                                   the client attempted several incompatible
- *                                   probes in parallel, then the most recent
- *                                   ones will be cancelled asynchronously.
- * * N_DHCP4_CLIENT_EVENT_LOG:       A logging event if n_dhcp4_client_set_log_level()
- *                                   is enabled.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_pop_event(NDhcp4Client *client, NDhcp4ClientEvent **eventp) {
-        NDhcp4CEventNode *node, *t_node;
-
-        c_list_for_each_entry_safe(node, t_node, &client->event_list, client_link) {
-                if (node->is_public) {
-                        n_dhcp4_c_event_node_free(node);
-                        continue;
-                }
-
-                node->is_public = true;
-                *eventp = &node->event;
-                return 0;
-        }
-
-        *eventp = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_update_mtu() - update link mtu
- * @client:                     client to operate on
- * @mtu:                        new mtu
- *
- * This updates the link MTU used by the client object. By default, the minimum
- * requirement given by the IP specification is assumed, which means 576
- * bytes. The caller is advised to update this to the actual MTU used by the
- * link layer.
- *
- * This value reflects the MTU of the link layer. That is, it is the maximum
- * packet size that you can send on that link, excluding the link-header but
- * including the IP-header. On ethernet-v2 this would be 1500.
- *
- * If unsure, it is safe to leave this unset. However, in this case a DHCP
- * server will be required to omit information if it does not fit into the
- * default MTU.
- *
- * Unless you keep the default MTU, you should update the MTU whenever the link
- * MTU changes. That is, when it is increased *and* when it is decreased.
- * However, you must be aware that decreasing the MTU on a link might cause
- * temporary data loss.
- *
- * Background: Knowing the link MTU guarantees that we can possibly transmit
- *             packets bigger than the IP minimum (i.e., 576 bytes). However,
- *             it does not guarantee that a possible target supports parsing
- *             packets bigger than the IP minimum. Hence, the MTU is used by a
- *             client to send a hint to a server that it can receive replies
- *             bigger than the minimum. As such, a server can reply with more
- *             information than otherwise possible.
- *             Since this DHCP client does not support fragmented packets, we
- *             simply set the allowed packet-size to the local link MTU.
- *             Note that DHCP relays might cause DHCP packets to be routed.
- *             However, such relays are required to always reassemble any
- *             fragments they receive into full DHCP packets, before they
- *             forward them either way. This guarantees that incoming packets
- *             are never fragmented, unless they exceed the local link MTU
- *             (this would otherwise not neccessarily be true, if some other
- *             part of the routed network had a lower MTU).
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_update_mtu(NDhcp4Client *client, uint16_t mtu) {
-        int r;
-
-        if (mtu == client->mtu)
-                return 0;
-
-        if (client->current_probe) {
-                r = n_dhcp4_client_probe_update_mtu(client->current_probe, mtu);
-                if (r)
-                        return r;
-        }
-
-        client->mtu = mtu;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe() - create a new probe
- * @client:                     client to operate on
- * @probep:                     output argument to store new probe
- * @config:                     probe configuration to use
- *
- * This creates a new probe on @client. Probes represent DHCP requests and
- * track the state over the entire lifetime of a lease. Once a probe is created
- * it will start looking for DHCP servers, request a lease from them, and renew
- * the lease continuously whenever it expires. Furthermore, if a lease cannot be
- * renewed, a new lease will be requested.
- *
- * The API allows for many probes to be run at the same time. However, the DHCP
- * specification forbids many of those cases (e.g., you must not reuse a client
- * id, otherwise it will be impossible to track who to forward received packets
- * to). Hence, so far only a single probe can run at a time. If you create a
- * new probe, all older probes that conflict with that probe will be canceled
- * (their state machine is halted and a N_DHCP4_CLIENT_EVENT_CANCELLED event is
- * raised.
- * This might change in the future, though. There might be cases where multiple
- * probes can be run in parallel (e.g., with different client-ids, or an INFORM
- * in parallel to a REQUEST, ...).
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_probe(NDhcp4Client *client,
-                                  NDhcp4ClientProbe **probep,
-                                  NDhcp4ClientProbeConfig *config) {
-        _c_cleanup_(n_dhcp4_client_probe_freep) NDhcp4ClientProbe *probe = NULL;
-        uint64_t ns_now;
-        int r;
-
-        ns_now = n_dhcp4_gettime(CLOCK_BOOTTIME);
-
-        r = n_dhcp4_client_probe_new(&probe, config, client, ns_now);
-        if (r)
-                return r;
-
-        n_dhcp4_client_arm_timer(client);
-
-        *probep = probe;
-        probe = NULL;
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-incoming.c b/shared/n-dhcp4/src/n-dhcp4-incoming.c
deleted file mode 100644
index f739413b..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-incoming.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * DHCPv4 Incoming Messages
- *
- * This file implements the message parser object for incoming DHCP4 messages.
- * It takes a linear data blob as input, and provides accessors for the message
- * content.
- *
- * This wrapper mainly deals with the OPTIONs array. That is, in hides the
- * different overload-sections the DHCP4 spec defines, it concatenates
- * duplicate option fields (as described by the spec), and provides a
- * consistent view to the caller.
- *
- * Internally, for every incoming message we linearize its OPTIONs. This means,
- * we create a copy of the contents, and merge all duplicate options into a
- * single option entry. We then provide accessors to the caller to easily get
- * O(1) access to individual fields.
- */
-
-#include <assert.h>
-#include <c-stdaux.h>
-#include <endian.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include "n-dhcp4.h"
-#include "n-dhcp4-private.h"
-
-static void n_dhcp4_incoming_prefetch(NDhcp4Incoming *incoming, size_t *offset, uint8_t option, const uint8_t *raw, size_t n_raw) {
-        uint8_t o, l;
-        size_t pos;
-
-        for (pos = 0; pos < n_raw; ) {
-                o = raw[pos++];
-                if (o == N_DHCP4_OPTION_PAD)
-                        continue;
-                if (o == N_DHCP4_OPTION_END)
-                        return;
-
-                /* bail out if no remaining space for length field */
-                if (pos >= n_raw)
-                        return;
-
-                /* bail out if length exceeds the available space */
-                l = raw[pos++];
-                if (l > n_raw || pos > n_raw - l)
-                        return;
-
-                /* prefetch content if it matches @option */
-                if (o == option) {
-                        memcpy((uint8_t *)&incoming->message + *offset, raw + pos, l);
-                        *offset += l;
-                }
-
-                pos += l;
-        }
-}
-
-static void n_dhcp4_incoming_merge(NDhcp4Incoming *incoming, size_t *offset, uint8_t overload, uint8_t option) {
-        uint8_t *m = (uint8_t *)&incoming->message;
-        size_t pos;
-
-        /*
-         * Prefetch all options matching @option from the 3 sections,
-         * concatenating their content. Remember the offset and size of the
-         * option in our message state.
-         */
-
-        pos = *offset;
-
-        /* prefetch option from OPTIONS */
-        n_dhcp4_incoming_prefetch(incoming, offset, option,
-                                  m + offsetof(NDhcp4Message, options),
-                                  incoming->n_message - offsetof(NDhcp4Message, options));
-
-        /* prefetch option from FILE */
-        if (overload & N_DHCP4_OVERLOAD_FILE)
-                n_dhcp4_incoming_prefetch(incoming, offset, option,
-                                          m + offsetof(NDhcp4Message, file),
-                                          sizeof(incoming->message.file));
-
-        /* prefetch option from SNAME */
-        if (overload & N_DHCP4_OVERLOAD_SNAME)
-                n_dhcp4_incoming_prefetch(incoming, offset, option,
-                                          m + offsetof(NDhcp4Message, sname),
-                                          sizeof(incoming->message.sname));
-
-        incoming->options[option].value = m + pos;
-        incoming->options[option].size = *offset - pos;
-}
-
-static void n_dhcp4_incoming_linearize(NDhcp4Incoming *incoming) {
-        uint8_t *m, o, l, overload;
-        size_t i, pos, end, offset;
-
-        /*
-         * Linearize all OPTIONs of the incoming message. We know that
-         * @incoming->message is preallocated to be big enough to hold the
-         * entire linearized message _trailing_ the original copy. All we have
-         * to do is walk the raw message in @incoming->message and for each
-         * option we find, copy it into the trailing space, concatenating all
-         * instances we find.
-         *
-         * Before we can copy the individual options, we must scan for the
-         * OVERLOAD option. This is required so our prefetcher knows which data
-         * arrays to scan for prefetching.
-         *
-         * So far, we require the OVERLOAD option to be present in the
-         * options-array (which is obvious and a given). However, if the option
-         * occurs multiple times outside of the options-array (i.e., SNAME or
-         * FILE), we silently ignore them. The specification does not allow
-         * multiple OVERLOAD options, anyway. Hence, this behavior only defines
-         * what we do when we see broken implementations, and we currently seem
-         * to support all styles we saw in the wild so far.
-         */
-
-        m = (uint8_t *)&incoming->message;
-        offset = incoming->n_message;
-
-        n_dhcp4_incoming_merge(incoming, &offset, 0, N_DHCP4_OPTION_OVERLOAD);
-        if (incoming->options[N_DHCP4_OPTION_OVERLOAD].size >= 1)
-                overload = *incoming->options[N_DHCP4_OPTION_OVERLOAD].value;
-        else
-                overload = 0;
-
-        for (i = 0; i < 3; ++i) {
-                if (i == 0) { /* walk OPTIONS */
-                        pos = offsetof(NDhcp4Message, options);
-                        end = incoming->n_message;
-                } else if (i == 1) { /* walk FILE */
-                        if (!(overload & N_DHCP4_OVERLOAD_FILE))
-                                continue;
-
-                        pos = offsetof(NDhcp4Message, file);
-                        end = pos + sizeof(incoming->message.file);
-                } else { /* walk SNAME */
-                        if (!(overload & N_DHCP4_OVERLOAD_SNAME))
-                                continue;
-
-                        pos = offsetof(NDhcp4Message, sname);
-                        end = pos + sizeof(incoming->message.sname);
-                }
-
-                while (pos < end) {
-                        o = m[pos++];
-                        if (o == N_DHCP4_OPTION_PAD)
-                                continue;
-                        if (o == N_DHCP4_OPTION_END)
-                                break;
-                        if (pos >= end)
-                                break;
-
-                        l = m[pos++];
-                        if (l > end || pos > end - l)
-                                break;
-
-                        if (!incoming->options[o].value)
-                                n_dhcp4_incoming_merge(incoming, &offset, overload, o);
-
-                        pos += l;
-                }
-        }
-}
-
-/**
- * n_dhcp4_incoming_new() - Allocate new incoming message object
- * @incomingp:          output argument for new object
- * @raw:                raw message blob
- * @n_raw:              length of the raw message blob
- *
- * This function allocates a new incoming-message object to wrap a received
- * message blob. It performs basic verification of the message length and
- * header, and then linearizes the DHCP4 options.
- *
- * The incoming-message object mainly provides accessors for the option-array.
- * It handles all the different quirks around parsing and concatenating the
- * options array, and provides the assembled data to the caller. It does not,
- * however, in any way interpret the data of the individual options. This is up
- * to the caller to do.
- *
- * Return: 0 on success, negative error code on failure, N_DHCP4_E_MALFORMED if
- *         the message is not a valid DHCP4 message.
- */
-int n_dhcp4_incoming_new(NDhcp4Incoming **incomingp, const void *raw, size_t n_raw) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *incoming = NULL;
-        size_t size;
-
-        if (n_raw < sizeof(NDhcp4Message) || n_raw > UINT16_MAX)
-                return N_DHCP4_E_MALFORMED;
-
-        /*
-         * Allocate enough space for book-keeping, a copy of @raw and trailing
-         * space for linearized options. The trailing space must be big enough
-         * to hold the entire options array unmodified (linearizing can only
-         * make it smaller). Hence, just allocate enough space to hold the raw
-         * message without the header.
-         */
-        size = sizeof(*incoming) + n_raw - sizeof(NDhcp4Message);
-        size += n_raw - sizeof(NDhcp4Header);
-
-        incoming = calloc(1, size);
-        if (!incoming)
-                return -ENOMEM;
-
-        *incoming = (NDhcp4Incoming)N_DHCP4_INCOMING_NULL(*incoming);
-        incoming->n_message = n_raw;
-        memcpy(&incoming->message, raw, n_raw);
-
-        if (incoming->message.magic != htobe32(N_DHCP4_MESSAGE_MAGIC))
-                return N_DHCP4_E_MALFORMED;
-
-        /* linearize options */
-        n_dhcp4_incoming_linearize(incoming);
-
-        *incomingp = incoming;
-        incoming = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_incoming_free() - Deallocate message object
- * @incoming:           object to operate on, or NULL
- *
- * This deallocates and frees the given incoming-message object. If NULL is
- * passed, this is a no-op.
- *
- * Return: NULL is returned.
- */
-NDhcp4Incoming *n_dhcp4_incoming_free(NDhcp4Incoming *incoming) {
-        if (!incoming)
-                return NULL;
-
-        free(incoming);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_incoming_get_header() - Return message header
- * @incoming:           message to operate on
- *
- * This returns a pointer to the message header. Note that modifications to
- * this header are permanent and will affect the original message.
- *
- * Return: A pointer to the message header is returned.
- */
-NDhcp4Header *n_dhcp4_incoming_get_header(NDhcp4Incoming *incoming) {
-        return &incoming->message.header;
-}
-
-/**
- * n_dhcp4_incoming_get_raw() - Get access to the raw original message
- * @incoming:           message to operate on
- * @rawp:               output argument for the raw blob, or NULL
- *
- * This hands out a pointer to the raw message blob to the caller. This will
- * point to the original message content, rather than the linearized version.
- *
- * Note that if the caller queried the contents of the message before, any
- * modifications done by the caller will not affect the original message. It
- * only affects the linearized content (which is a duplicate trailing the
- * original message). However, modifications to the message header *DO* also
- * appear in the original, since the message header is not duplicated.
- *
- * In either case, it is better to never modify the message, if you intend to
- * forward it further.
- *
- * Return: The length of the raw message blob is returned.
- */
-size_t n_dhcp4_incoming_get_raw(NDhcp4Incoming *incoming, const void **rawp) {
-        if (rawp)
-                *rawp = &incoming->message;
-        return incoming->n_message;
-}
-
-/**
- * n_dhcp4_incoming_query() - Query the contents of a specific option
- * @incoming:           message to query
- * @option:             option to look for
- * @datap:              output argument for the option-data, or NULL
- * @n_datap:            output argument for the length of the option, or NULL
- *
- * This returns a pointer to the requested option blob in the message. It
- * points to a linearized version of all respective option-fields of the same
- * type. Hence, the caller is not required to deal with multiple occurrences of
- * the same option.
- *
- * If an option was not present in the incoming message, N_DHCP4_E_UNSET is
- * returned. Note that this is different from an empty option! And empty option
- * will return a valid pointer and size 0.
- *
- * Note that the pointer to the option-blob does not point to the original
- * message, but a duplicated version. Modifications to the blob will not be
- * reflected in the original message, but they will be permanent regarding
- * further queries through this function.
- *
- * Note that the original message alignment might no longer be reflected in the
- * returned blob. You must not alias the content of the blob, but always copy
- * it out, or consume piecemeal.
- *
- * This function runs in O(1).
- *
- * Return: 0 on success, negative error code on failure, N_DHCP4_E_UNSET if the
- *         option was not found,
- */
-int n_dhcp4_incoming_query(NDhcp4Incoming *incoming, uint8_t option, uint8_t **datap, size_t *n_datap) {
-        if (!incoming->options[option].value)
-                return N_DHCP4_E_UNSET;
-
-        if (datap)
-                *datap = incoming->options[option].value;
-        if (n_datap)
-                *n_datap = incoming->options[option].size;
-        return 0;
-}
-
-static int n_dhcp4_incoming_query_u8(NDhcp4Incoming *message, uint8_t option, uint8_t *u8p) {
-        uint8_t *data;
-        size_t n_data;
-        int r;
-
-        r = n_dhcp4_incoming_query(message, option, &data, &n_data);
-        if (r)
-                return r;
-        else if (n_data < sizeof(*data))
-                return N_DHCP4_E_MALFORMED;
-
-        *u8p = *data;
-        return 0;
-}
-
-static int n_dhcp4_incoming_query_u16(NDhcp4Incoming *message, uint8_t option, uint16_t *u16p) {
-        uint8_t *data;
-        size_t n_data;
-        uint16_t be16;
-        int r;
-
-        r = n_dhcp4_incoming_query(message, option, &data, &n_data);
-        if (r)
-                return r;
-        else if (n_data < sizeof(be16))
-                return N_DHCP4_E_MALFORMED;
-
-        memcpy(&be16, data, sizeof(be16));
-
-        *u16p = ntohs(be16);
-        return 0;
-}
-
-static int n_dhcp4_incoming_query_u32(NDhcp4Incoming *message, uint8_t option, uint32_t *u32p) {
-        uint8_t *data;
-        size_t n_data;
-        uint32_t be32;
-        int r;
-
-        r = n_dhcp4_incoming_query(message, option, &data, &n_data);
-        if (r)
-                return r;
-        else if (n_data < sizeof(be32))
-                return N_DHCP4_E_MALFORMED;
-
-        memcpy(&be32, data, sizeof(be32));
-
-        *u32p = ntohl(be32);
-        return 0;
-}
-
-static int n_dhcp4_incoming_query_in_addr(NDhcp4Incoming *message, uint8_t option, struct in_addr *addrp) {
-        uint8_t *data;
-        size_t n_data;
-        uint32_t be32;
-        int r;
-
-        r = n_dhcp4_incoming_query(message, option, &data, &n_data);
-        if (r)
-                return r;
-        else if (n_data < sizeof(be32))
-                return N_DHCP4_E_MALFORMED;
-
-        memcpy(&be32, data, sizeof(be32));
-
-        addrp->s_addr = be32;
-        return 0;
-}
-
-int n_dhcp4_incoming_query_message_type(NDhcp4Incoming *message, uint8_t *typep) {
-        return n_dhcp4_incoming_query_u8(message, N_DHCP4_OPTION_MESSAGE_TYPE, typep);
-}
-
-int n_dhcp4_incoming_query_lifetime(NDhcp4Incoming *message, uint32_t *lifetimep) {
-        return n_dhcp4_incoming_query_u32(message, N_DHCP4_OPTION_IP_ADDRESS_LEASE_TIME, lifetimep);
-}
-
-int n_dhcp4_incoming_query_t2(NDhcp4Incoming *message, uint32_t *t2p) {
-        return n_dhcp4_incoming_query_u32(message, N_DHCP4_OPTION_REBINDING_T2_TIME, t2p);
-}
-
-int n_dhcp4_incoming_query_t1(NDhcp4Incoming *message, uint32_t *t1p) {
-        return n_dhcp4_incoming_query_u32(message, N_DHCP4_OPTION_RENEWAL_T1_TIME, t1p);
-}
-
-int n_dhcp4_incoming_query_server_identifier(NDhcp4Incoming *message, struct in_addr *idp) {
-        return n_dhcp4_incoming_query_in_addr(message, N_DHCP4_OPTION_SERVER_IDENTIFIER, idp);
-}
-
-int n_dhcp4_incoming_query_max_message_size(NDhcp4Incoming *message, uint16_t *max_message_sizep) {
-        return n_dhcp4_incoming_query_u16(message, N_DHCP4_OPTION_MAXIMUM_MESSAGE_SIZE, max_message_sizep);
-}
-
-int n_dhcp4_incoming_query_requested_ip(NDhcp4Incoming *message, struct in_addr *requested_ipp) {
-        return n_dhcp4_incoming_query_in_addr(message, N_DHCP4_OPTION_REQUESTED_IP_ADDRESS, requested_ipp);
-}
-
-void n_dhcp4_incoming_get_xid(NDhcp4Incoming *message, uint32_t *xidp) {
-        NDhcp4Header *header = n_dhcp4_incoming_get_header(message);
-
-        *xidp = header->xid;
-}
-
-void n_dhcp4_incoming_get_yiaddr(NDhcp4Incoming *message, struct in_addr *yiaddr) {
-        NDhcp4Header *header = n_dhcp4_incoming_get_header(message);
-
-        yiaddr->s_addr = header->yiaddr;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-outgoing.c b/shared/n-dhcp4/src/n-dhcp4-outgoing.c
deleted file mode 100644
index bcab407f..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-outgoing.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * DHCPv4 Outgoing Messages
- *
- * XXX
- */
-
-#include <assert.h>
-#include <c-stdaux.h>
-#include <endian.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include "n-dhcp4.h"
-#include "n-dhcp4-private.h"
-
-/**
- * N_DHCP4_OUTGOING_MAX_PHDR - maximum protocol header size
- *
- * All DHCP4 messages-limits specify the size of the entire packet including
- * the protocol layer (i.e., including the IP headers and UDP headers). To
- * calculate the size we have remaining for the actual DHCP message, we need to
- * substract the maximum possible header-length the linux-kernel might prepend
- * to our messages. This turns out to be the maximum IP-header size (including
- * optional IP headers, hence 60 bytes) plus the UDP header size (i.e., 8
- * bytes).
- */
-#define N_DHCP4_OUTGOING_MAX_PHDR (N_DHCP4_NETWORK_IP_MAXIMUM_HEADER_SIZE + sizeof(struct udphdr))
-
-/**
- * n_dhcp4_outgoing_new() - Allocate new outgoing message
- * @outgoingp:          output argument to return allocate object through
- * @max_size:           maximum transmission size to use
- * @overload:           select sections to overload
- *
- * This allocates a new outgoing message and returns it to the caller. The
- * caller can then append data to it and send it over the wire.
- *
- * The @max_size parameter specifies the transport-layer MTU to consider. If 0,
- * N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE is used. Note that this argument
- * specifies the maximum packet size *INCLUDING* the IP-headers and UDP-header.
- * Internally, the allocator makes sure to never create packets bigger than the
- * specified MTU. The append functions will return an error, if the packet size
- * would exceed the MTU.
- * If you use a full UDP stack that supports packet fragmentation, you can
- * specify the maximum packet size here (e.g., UINT16_MAX).
- *
- * Return: 0 on success, error code on failure.
- */
-int n_dhcp4_outgoing_new(NDhcp4Outgoing **outgoingp, size_t max_size, uint8_t overload) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *outgoing = NULL;
-
-        /*
-         * Make sure the minimum limit is bigger than the maximum protocol
-         * header plus the DHCP-message-header plus a single OPTION_END byte.
-         */
-        static_assert(N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE >= N_DHCP4_OUTGOING_MAX_PHDR +
-                                                             sizeof(NDhcp4Message) + 1,
-                      "Invalid minimum IP packet limit");
-
-        c_assert(!(overload & ~(N_DHCP4_OVERLOAD_FILE | N_DHCP4_OVERLOAD_SNAME)));
-
-        outgoing = calloc(1, sizeof(*outgoing));
-        if (!outgoing)
-                return -ENOMEM;
-
-        *outgoing = (NDhcp4Outgoing)N_DHCP4_OUTGOING_NULL(*outgoing);
-        outgoing->n_message = N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE - N_DHCP4_OUTGOING_MAX_PHDR;
-        outgoing->i_message = offsetof(NDhcp4Message, options);
-        outgoing->max_size = outgoing->n_message;
-        outgoing->overload = overload;
-
-        if (max_size > N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE)
-                outgoing->max_size = max_size - N_DHCP4_OUTGOING_MAX_PHDR;
-
-        outgoing->message = calloc(1, outgoing->n_message);
-        if (!outgoing->message)
-                return -ENOMEM;
-
-        outgoing->message->magic = htonl(N_DHCP4_MESSAGE_MAGIC);
-        outgoing->message->options[0] = N_DHCP4_OPTION_END;
-
-        *outgoingp = outgoing;
-        outgoing = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_outgoing_free() - Deallocate outgoing message
- * @outgoing:           message to deallocate, or NULL
- *
- * This is the opposite to n_dhcp4_outgoing_new(). It deallocates and frees the
- * passed object. If @outgoing is NULL, this is a no-op.
- *
- * Return: NULL is returned.
- */
-NDhcp4Outgoing *n_dhcp4_outgoing_free(NDhcp4Outgoing *outgoing) {
-        if (!outgoing)
-                return NULL;
-
-        free(outgoing->message);
-        free(outgoing);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_outgoing_get_header() - Get pointer to the message header
- * @outgoing:           message to operate on
- *
- * This returns a pointer to the DHCP4 message header to the caller. The caller
- * can use this to fill-in the header-fields. Note that all fields are
- * initialized to their default values. Hence, you only need to override the
- * fields where the default is not sufficient.
- *
- * Return: A pointer to the message header is returned.
- */
-NDhcp4Header *n_dhcp4_outgoing_get_header(NDhcp4Outgoing *outgoing) {
-        return &outgoing->message->header;
-}
-
-/**
- * n_dhcp4_outgoing_get_raw() - Get the raw message blob
- * @outgoing:           message to operat on
- * @rawp:               output argument for the message-blob
- *
- * This function gives the caller access to the raw message-blob. That is, once
- * message-marshaling is complete, use this to get the raw blob for sending.
- * Note that this blob is only valid as long as you no longer append any
- * further options to the message, nor modify it in any other way.
- *
- * Return: The size of the raw message blob is returned.
- */
-size_t n_dhcp4_outgoing_get_raw(NDhcp4Outgoing *outgoing, const void **rawp) {
-        if (rawp)
-                *rawp = outgoing->message;
-
-        /*
-         * Return the DHCP message until the END option, excluding any
-         * trailing padding. We overallocate during append, so the
-         * allocated message might be bigger than what we want to
-         * send on the wire.
-         */
-        return outgoing->i_message + 1;
-}
-
-static void n_dhcp4_outgoing_append_option(NDhcp4Outgoing *outgoing,
-                                           uint8_t option,
-                                           const void *data,
-                                           uint8_t n_data) {
-        uint8_t *blob = (void *)outgoing->message;
-
-        blob[outgoing->i_message++] = option;
-        blob[outgoing->i_message++] = n_data;
-        memcpy(blob + outgoing->i_message, data, n_data);
-        outgoing->i_message += n_data;
-        blob[outgoing->i_message] = N_DHCP4_OPTION_END;
-}
-
-/**
- * n_dhcp4_outgoing_append() - Append option to outgoing message
- * @outgoing:           message to operate on
- * @option:             option code to append
- * @data:               data to append in the option
- * @n_data:             length of the data blob
- *
- * This appends another option to the given outgoing message. The data is taken
- * verbatim and copied into the message. Note that no validation is done. If
- * you provide an option multiple times, it will be added multiple times (spec
- * then requires them to be interpreted as concatenated option, in case the
- * option is marked as such).
- *
- * The size of a message is limited, based on the restriction passed to the
- * outgoing-message constructor. If there is not enough free space to copy in
- * the new option, N_DHCP4_E_NO_SPACE is returned.
- *
- * The order in which you append options might matter to some implementations.
- * For example, the message-type is often expected to be the first option. We
- * do not place such restrictions, but for compatibility with external
- * implementations, you should follow these recommendations.
- * Furthermore, we do not implement any kind of smart allocators. That is, all
- * options are simply appended when you call this. But due to the overloading
- * feature, fragmentation might matter. Hence, if you use overloading, overly
- * big options might cause padding, and as such waste space.
- *
- * Return: 0 on success, negative error code on failure, N_DHCP4_E_NO_SPACE
- *         when there is not sufficient free space in the message.
- */
-int n_dhcp4_outgoing_append(NDhcp4Outgoing *outgoing,
-                            uint8_t option,
-                            const void *data,
-                            uint8_t n_data) {
-        NDhcp4Message *m;
-        uint8_t overload;
-        size_t rem, n;
-
-        c_assert(option != N_DHCP4_OPTION_PAD);
-        c_assert(option != N_DHCP4_OPTION_END);
-        c_assert(option != N_DHCP4_OPTION_OVERLOAD);
-
-        /*
-         * If the iterator is on the OPTIONs field, try appending the new blob.
-         * We need 2 header-bytes plus @n_data bytes. Additionally, we always
-         * reserve 3 trailing bytes for a possible OVERLOAD option, and 1 byte
-         * for the END marker.
-         */
-        if (outgoing->i_message >= offsetof(NDhcp4Message, options)) {
-                rem = outgoing->n_message - outgoing->i_message;
-
-                /* try fitting into remaining OPTIONs space */
-                if (rem >= n_data + 2U + 3U + 1U) {
-                        n_dhcp4_outgoing_append_option(outgoing, option, data, n_data);
-                        return 0;
-                }
-
-                /* try fitting into allowed OPTIONs space */
-                if (outgoing->max_size - outgoing->i_message >= n_data + 2U + 3U + 1U) {
-                        /* try over-allocation to reduce allocation pressure */
-                        n = outgoing->n_message + n_data + 128;
-                        if (n > outgoing->max_size)
-                                n = outgoing->max_size;
-                        m = realloc(outgoing->message, n);
-                        if (!m)
-                                return -ENOMEM;
-
-                        memset((void *)m + outgoing->i_message, 0, n - outgoing->i_message);
-                        outgoing->message = m;
-                        outgoing->n_message = n;
-                        n_dhcp4_outgoing_append_option(outgoing, option, data, n_data);
-                        return 0;
-                }
-
-                /* not enough remaining space, try OVERLOAD */
-                if (!outgoing->overload)
-                        return N_DHCP4_E_NO_SPACE;
-
-                /*
-                 * We ran out of space in the OPTIONs array, but overloading
-                 * was enabled. This means, we can insert an OVERLOAD option
-                 * and then use SNAME/FILE to store more options.
-                 * Note that the three different sections cannot overlap and
-                 * all must have an END marker. So as soon as we add the
-                 * OVERLOAD option, we must make sure the other sections have
-                 * the valid END marker. From then on, our *_append_option()
-                 * helper makes sure to move the END marker with every
-                 * insertion.
-                 */
-                overload = outgoing->overload;
-                n_dhcp4_outgoing_append_option(outgoing, N_DHCP4_OPTION_OVERLOAD, &overload, 1);
-
-                if (overload & N_DHCP4_OVERLOAD_FILE)
-                        outgoing->message->file[0] = N_DHCP4_OPTION_END;
-                if (overload & N_DHCP4_OVERLOAD_SNAME)
-                        outgoing->message->sname[0] = N_DHCP4_OPTION_END;
-
-                if (overload & N_DHCP4_OVERLOAD_FILE)
-                        outgoing->i_message = offsetof(NDhcp4Message, file);
-                else if (overload & N_DHCP4_OVERLOAD_SNAME)
-                        outgoing->i_message = offsetof(NDhcp4Message, sname);
-        }
-
-        /*
-         * The OPTIONs section is full and OVERLOAD was enabled. Try writing
-         * into the FILE section. Always reserve 1 byte for the trailing END
-         * marker.
-         */
-        if (outgoing->i_message >= offsetof(NDhcp4Message, file)) {
-                rem = sizeof(outgoing->message->file);
-                rem -= outgoing->i_message - offsetof(NDhcp4Message, file);
-
-                if (rem >= n_data + 2U + 1U) {
-                        n_dhcp4_outgoing_append_option(outgoing, option, data, n_data);
-                        return 0;
-                }
-
-                overload = outgoing->overload;
-                if (overload & N_DHCP4_OVERLOAD_SNAME)
-                        outgoing->i_message = offsetof(NDhcp4Message, sname);
-                else
-                        return N_DHCP4_E_NO_SPACE;
-        }
-
-        /*
-         * OPTIONs and FILE are full, try putting data into the SNAME section
-         * as a last resort.
-         */
-        if (outgoing->i_message >= offsetof(NDhcp4Message, sname)) {
-                rem = sizeof(outgoing->message->sname);
-                rem -= outgoing->i_message - offsetof(NDhcp4Message, sname);
-
-                if (rem >= n_data + 2U + 1U) {
-                        n_dhcp4_outgoing_append_option(outgoing, option, data, n_data);
-                        return 0;
-                }
-        }
-
-        return N_DHCP4_E_NO_SPACE;
-}
-
-static int n_dhcp4_outgoing_append_u32(NDhcp4Outgoing *message, uint8_t option, uint32_t u32) {
-        uint32_t be32 = htonl(u32);
-        int r;
-
-        r = n_dhcp4_outgoing_append(message, option, &be32, sizeof(be32));
-        if (r)
-                return r;
-
-        return 0;
-}
-
-static int n_dhcp4_outgoing_append_in_addr(NDhcp4Outgoing *message, uint8_t option, struct in_addr addr) {
-        int r;
-
-        r = n_dhcp4_outgoing_append(message, option, &addr.s_addr, sizeof(addr.s_addr));
-        if (r)
-                return r;
-
-        return 0;
-}
-
-int n_dhcp4_outgoing_append_t1(NDhcp4Outgoing *message, uint32_t t1) {
-        return n_dhcp4_outgoing_append_u32(message, N_DHCP4_OPTION_RENEWAL_T1_TIME, t1);
-}
-
-int n_dhcp4_outgoing_append_t2(NDhcp4Outgoing *message, uint32_t t2) {
-        return n_dhcp4_outgoing_append_u32(message, N_DHCP4_OPTION_REBINDING_T2_TIME, t2);
-}
-
-int n_dhcp4_outgoing_append_lifetime(NDhcp4Outgoing *message, uint32_t lifetime) {
-        return n_dhcp4_outgoing_append_u32(message, N_DHCP4_OPTION_IP_ADDRESS_LEASE_TIME, lifetime);
-}
-
-int n_dhcp4_outgoing_append_server_identifier(NDhcp4Outgoing *message, struct in_addr addr) {
-        return n_dhcp4_outgoing_append_in_addr(message, N_DHCP4_OPTION_SERVER_IDENTIFIER, addr);
-}
-
-int n_dhcp4_outgoing_append_requested_ip(NDhcp4Outgoing *message, struct in_addr addr) {
-        return n_dhcp4_outgoing_append_in_addr(message, N_DHCP4_OPTION_REQUESTED_IP_ADDRESS, addr);
-}
-
-void n_dhcp4_outgoing_set_secs(NDhcp4Outgoing *message, uint16_t secs) {
-        NDhcp4Header *header = n_dhcp4_outgoing_get_header(message);
-
-        /*
-         * Some DHCP servers will reject DISCOVER or REQUEST messages if 'secs'
-         * is not set (i.e., set to 0), even though the spec allows it.
-         */
-        c_assert(secs);
-
-        header->secs = htons(secs);
-}
-
-void n_dhcp4_outgoing_set_xid(NDhcp4Outgoing *message, uint32_t xid) {
-        NDhcp4Header *header = n_dhcp4_outgoing_get_header(message);
-
-        header->xid = xid;
-}
-
-void n_dhcp4_outgoing_get_xid(NDhcp4Outgoing *message, uint32_t *xidp) {
-        NDhcp4Header *header = n_dhcp4_outgoing_get_header(message);
-
-        *xidp = header->xid;
-}
-
-void n_dhcp4_outgoing_set_yiaddr(NDhcp4Outgoing *message, struct in_addr yiaddr) {
-        NDhcp4Header *header = n_dhcp4_outgoing_get_header(message);
-
-        header->yiaddr = yiaddr.s_addr;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-private.h b/shared/n-dhcp4/src/n-dhcp4-private.h
deleted file mode 100644
index db7b24ff..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-private.h
+++ /dev/null
@@ -1,759 +0,0 @@
-#pragma once
-
-#include <arpa/inet.h>
-#include <assert.h>
-#include <c-list.h>
-#include <c-stdaux.h>
-#include <endian.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-#include <syslog.h>
-#include "n-dhcp4.h"
-
-typedef struct NDhcp4CConnection NDhcp4CConnection;
-typedef struct NDhcp4CEventNode NDhcp4CEventNode;
-typedef struct NDhcp4ClientProbeOption NDhcp4ClientProbeOption;
-typedef struct NDhcp4Header NDhcp4Header;
-typedef struct NDhcp4Incoming NDhcp4Incoming;
-typedef struct NDhcp4Message NDhcp4Message;
-typedef struct NDhcp4Outgoing NDhcp4Outgoing;
-typedef struct NDhcp4SConnection NDhcp4SConnection;
-typedef struct NDhcp4SConnectionIp NDhcp4SConnectionIp;
-typedef struct NDhcp4SEventNode NDhcp4SEventNode;
-typedef struct NDhcp4LogQueue NDhcp4LogQueue;
-
-/* specs */
-
-#define N_DHCP4_NETWORK_IP_MAXIMUM_HEADER_SIZE (60) /* See RFC791 */
-#define N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE (576) /* See RFC791 */
-#define N_DHCP4_NETWORK_SERVER_PORT (67)
-#define N_DHCP4_NETWORK_CLIENT_PORT (68)
-#define N_DHCP4_MESSAGE_MAGIC ((uint32_t)(0x63825363))
-#define N_DHCP4_MESSAGE_FLAG_BROADCAST (htons(0x8000))
-
-enum {
-        N_DHCP4_OP_BOOTREQUEST                          = 1,
-        N_DHCP4_OP_BOOTREPLY                            = 2,
-};
-
-enum {
-        N_DHCP4_OPTION_PAD                              = 0,
-        N_DHCP4_OPTION_SUBNET_MASK                      = 1,
-        N_DHCP4_OPTION_TIME_OFFSET                      = 2,
-        N_DHCP4_OPTION_ROUTER                           = 3,
-        N_DHCP4_OPTION_DOMAIN_NAME_SERVER               = 6,
-        N_DHCP4_OPTION_HOST_NAME                        = 12,
-        N_DHCP4_OPTION_BOOT_FILE_SIZE                   = 13,
-        N_DHCP4_OPTION_DOMAIN_NAME                      = 15,
-        N_DHCP4_OPTION_ROOT_PATH                        = 17,
-        N_DHCP4_OPTION_ENABLE_IP_FORWARDING             = 19,
-        N_DHCP4_OPTION_ENABLE_IP_FORWARDING_NL          = 20,
-        N_DHCP4_OPTION_POLICY_FILTER                    = 21,
-        N_DHCP4_OPTION_INTERFACE_MDR                    = 22,
-        N_DHCP4_OPTION_INTERFACE_TTL                    = 23,
-        N_DHCP4_OPTION_INTERFACE_MTU_AGING_TIMEOUT      = 24,
-        N_DHCP4_OPTION_INTERFACE_MTU                    = 26,
-        N_DHCP4_OPTION_BROADCAST                        = 28,
-        N_DHCP4_OPTION_STATIC_ROUTE                     = 33,
-        N_DHCP4_OPTION_NTP_SERVER                       = 42,
-        N_DHCP4_OPTION_VENDOR_SPECIFIC                  = 43,
-        N_DHCP4_OPTION_REQUESTED_IP_ADDRESS             = 50,
-        N_DHCP4_OPTION_IP_ADDRESS_LEASE_TIME            = 51,
-        N_DHCP4_OPTION_OVERLOAD                         = 52,
-        N_DHCP4_OPTION_MESSAGE_TYPE                     = 53,
-        N_DHCP4_OPTION_SERVER_IDENTIFIER                = 54,
-        N_DHCP4_OPTION_PARAMETER_REQUEST_LIST           = 55,
-        N_DHCP4_OPTION_ERROR_MESSAGE                    = 56,
-        N_DHCP4_OPTION_MAXIMUM_MESSAGE_SIZE             = 57,
-        N_DHCP4_OPTION_RENEWAL_T1_TIME                  = 58,
-        N_DHCP4_OPTION_REBINDING_T2_TIME                = 59,
-        N_DHCP4_OPTION_VENDOR_CLASS_IDENTIFIER          = 60,
-        N_DHCP4_OPTION_CLIENT_IDENTIFIER                = 61,
-        N_DHCP4_OPTION_FQDN                             = 81,
-        N_DHCP4_OPTION_NEW_POSIX_TIMEZONE               = 100,
-        N_DHCP4_OPTION_NEW_TZDB_TIMEZONE                = 101,
-        N_DHCP4_OPTION_CLASSLESS_STATIC_ROUTE           = 121,
-        N_DHCP4_OPTION_PRIVATE_BASE                     = 224,
-        N_DHCP4_OPTION_PRIVATE_LAST                     = 254,
-        N_DHCP4_OPTION_END                              = 255,
-        _N_DHCP4_OPTION_N                               = 256,
-};
-
-enum {
-        N_DHCP4_OVERLOAD_FILE                           = 1,
-        N_DHCP4_OVERLOAD_SNAME                          = 2,
-};
-
-enum {
-        N_DHCP4_MESSAGE_DISCOVER                        = 1,
-        N_DHCP4_MESSAGE_OFFER                           = 2,
-        N_DHCP4_MESSAGE_REQUEST                         = 3,
-        N_DHCP4_MESSAGE_DECLINE                         = 4,
-        N_DHCP4_MESSAGE_ACK                             = 5,
-        N_DHCP4_MESSAGE_NAK                             = 6,
-        N_DHCP4_MESSAGE_RELEASE                         = 7,
-        N_DHCP4_MESSAGE_INFORM                          = 8,
-        N_DHCP4_MESSAGE_FORCERENEW                      = 9,
-};
-
-struct NDhcp4Header {
-        uint8_t op;
-        uint8_t htype;
-        uint8_t hlen;
-        uint8_t hops;
-        uint32_t xid;
-        uint16_t secs;
-        uint16_t flags;
-        uint32_t ciaddr;
-        uint32_t yiaddr;
-        uint32_t siaddr;
-        uint32_t giaddr;
-        uint8_t chaddr[16];
-} _c_packed_;
-
-struct NDhcp4Message {
-        NDhcp4Header header;
-        uint8_t sname[64];
-        uint8_t file[128];
-        uint32_t magic;
-        uint8_t options[];
-} _c_packed_;
-
-/* objects */
-
-enum {
-        _N_DHCP4_E_INTERNAL = _N_DHCP4_E_N,
-
-        N_DHCP4_E_UNEXPECTED,
-
-        N_DHCP4_E_NO_SPACE,
-        N_DHCP4_E_MALFORMED,
-
-        N_DHCP4_E_DROPPED,
-        N_DHCP4_E_DOWN,
-        N_DHCP4_E_AGAIN,
-};
-
-enum {
-        N_DHCP4_C_CONNECTION_STATE_INIT,
-        N_DHCP4_C_CONNECTION_STATE_PACKET,
-        N_DHCP4_C_CONNECTION_STATE_DRAINING,
-        N_DHCP4_C_CONNECTION_STATE_UDP,
-        N_DHCP4_C_CONNECTION_STATE_CLOSED,
-};
-
-enum {
-        N_DHCP4_CLIENT_EPOLL_TIMER,
-        N_DHCP4_CLIENT_EPOLL_IO,
-};
-
-enum {
-        N_DHCP4_CLIENT_PROBE_STATE_INIT,
-        N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT,
-        N_DHCP4_CLIENT_PROBE_STATE_SELECTING,
-        N_DHCP4_CLIENT_PROBE_STATE_REBOOTING,
-        N_DHCP4_CLIENT_PROBE_STATE_REQUESTING,
-        N_DHCP4_CLIENT_PROBE_STATE_GRANTED,
-        N_DHCP4_CLIENT_PROBE_STATE_BOUND,
-        N_DHCP4_CLIENT_PROBE_STATE_RENEWING,
-        N_DHCP4_CLIENT_PROBE_STATE_REBINDING,
-        N_DHCP4_CLIENT_PROBE_STATE_EXPIRED,
-};
-
-enum {
-        N_DHCP4_CLIENT_LEASE_STATE_INIT,
-        N_DHCP4_CLIENT_LEASE_STATE_OFFERED,
-        N_DHCP4_CLIENT_LEASE_STATE_SELECTED,
-        N_DHCP4_CLIENT_LEASE_STATE_DECLINED,
-        N_DHCP4_CLIENT_LEASE_STATE_ACKED,
-};
-
-enum {
-        N_DHCP4_SERVER_EPOLL_TIMER,
-        N_DHCP4_SERVER_EPOLL_IO,
-};
-
-enum {
-        _N_DHCP4_C_MESSAGE_INVALID = 0,
-        N_DHCP4_C_MESSAGE_DISCOVER,
-        N_DHCP4_C_MESSAGE_INFORM,
-        N_DHCP4_C_MESSAGE_SELECT,
-        N_DHCP4_C_MESSAGE_IGNORE,
-        N_DHCP4_C_MESSAGE_RENEW,
-        N_DHCP4_C_MESSAGE_REBIND,
-        N_DHCP4_C_MESSAGE_REBOOT,
-        N_DHCP4_C_MESSAGE_RELEASE,
-        N_DHCP4_C_MESSAGE_DECLINE,
-};
-
-struct NDhcp4Outgoing {
-        NDhcp4Message *message;
-        size_t n_message;
-        size_t i_message;
-        size_t max_size;
-
-        uint8_t overload : 2;
-
-        struct {
-                uint8_t type;
-                uint8_t message_type;
-                uint32_t client_addr;
-                uint64_t start_time;
-                uint64_t base_time;
-                uint64_t send_time;
-                uint64_t send_jitter;
-                size_t n_send;
-        } userdata;
-};
-
-#define N_DHCP4_OUTGOING_NULL(_x) {                                             \
-        }
-
-struct NDhcp4Incoming {
-        struct {
-                uint8_t *value;
-                size_t size;
-        } options[_N_DHCP4_OPTION_N];
-
-        struct {
-                uint8_t type;
-                uint64_t start_time;
-                uint64_t base_time;
-        } userdata;
-
-        size_t n_message;
-        NDhcp4Message message;
-        /* @message must be the last member */
-};
-
-#define N_DHCP4_INCOMING_NULL(_x) {                                             \
-        }
-
-struct NDhcp4ClientConfig {
-        int ifindex;
-        unsigned int transport;
-        bool request_broadcast;
-        uint8_t mac[32]; /* MAX_ADDR_LEN */
-        size_t n_mac;
-        uint8_t broadcast_mac[32]; /* MAX_ADDR_LEN */
-        size_t n_broadcast_mac;
-        uint8_t *client_id;
-        size_t n_client_id;
-};
-
-#define N_DHCP4_CLIENT_CONFIG_NULL(_x) {                                        \
-                .transport = _N_DHCP4_TRANSPORT_N,                              \
-        }
-
-struct NDhcp4ClientProbeOption {
-        uint8_t option;
-        uint8_t n_data;
-        uint8_t data[];
-};
-
-#define N_DHCP4_CLIENT_PROBE_OPTION_NULL(_x) {                                  \
-                .option = N_DHCP4_OPTION_PAD,                                   \
-        }
-
-struct NDhcp4ClientProbeConfig {
-        bool inform_only;
-        bool init_reboot;
-        struct in_addr requested_ip;
-        unsigned short int entropy[3];
-        uint64_t ms_start_delay;        /* max ms to wait before starting probe */
-        NDhcp4ClientProbeOption *options[UINT8_MAX + 1];
-        int8_t request_parameters[UINT8_MAX + 1];
-        size_t n_request_parameters;
-};
-
-#define N_DHCP4_CLIENT_PROBE_CONFIG_NULL(_x) {                                  \
-                .ms_start_delay = N_DHCP4_CLIENT_START_DELAY_RFC2131,           \
-        }
-
-struct NDhcp4CEventNode {
-        CList client_link;
-        CList probe_link;
-        NDhcp4ClientEvent event;
-        bool is_public : 1;
-};
-
-#define N_DHCP4_C_EVENT_NODE_NULL(_x) {                                         \
-                .client_link = C_LIST_INIT((_x).client_link),                   \
-                .probe_link = C_LIST_INIT((_x).probe_link),                     \
-        }
-
-struct NDhcp4LogQueue {
-        CList *event_list;
-        NDhcp4CEventNode nomem_node;
-        int log_level;
-        bool is_client : 1;
-};
-
-#define N_DHCP4_LOG_QUEUE_NULL_DEFUNCT() {                                      \
-                .log_level = -1,                                                \
-                .is_client = false,                                             \
-        }
-
-#define N_DHCP4_LOG_QUEUE_NULL_CLIENT(client) {                                 \
-                .event_list = &((client).event_list),                           \
-                .log_level = -1,                                                \
-                .is_client = true,                                              \
-                .nomem_node = {                                                 \
-                        .client_link = C_LIST_INIT((client).log_queue.nomem_node.client_link), \
-                        .probe_link = C_LIST_INIT((client).log_queue.nomem_node.probe_link), \
-                        .event = {                                              \
-                                .event = N_DHCP4_CLIENT_EVENT_LOG,              \
-                                .log = {                                        \
-                                        .level = LOG_CRIT,                      \
-                                        .message = "one or more logging messages dropped due to out of memory", \
-                                        .allow_steal_message = false,           \
-                                },                                              \
-                        },                                                      \
-                        .is_public = false,                                     \
-                },                                                              \
-        }
-
-struct NDhcp4CConnection {
-        NDhcp4ClientConfig *client_config;
-        NDhcp4ClientProbeConfig *probe_config;
-        NDhcp4LogQueue *log_queue;
-
-        int fd_epoll;
-
-        unsigned int state;             /* current connection state */
-        int fd_packet;                  /* packet socket */
-        int fd_udp;                     /* udp socket */
-
-        NDhcp4Outgoing *request;        /* current request */
-
-        uint32_t client_ip;             /* client IP address, or 0 */
-        uint32_t server_ip;             /* server IP address, or 0 */
-        uint16_t mtu;                   /* client mtu, or 0 */
-
-        /*
-         * When we get DHCP packets from the kernel, we need a buffer to read
-         * the data into. Since UDP packets can be up to 2^16 bytes in size, we
-         * avoid placing it on the stack and instead read into this scratch
-         * buffer. It is purely meant as stack replacement, no data is returned
-         * through this buffer.
-         */
-        uint8_t scratch_buffer[UINT16_MAX];
-};
-
-#define N_DHCP4_C_CONNECTION_NULL(_x) {                                         \
-                .fd_packet = -1,                                                \
-                .fd_udp = -1,                                                   \
-        }
-
-struct NDhcp4Client {
-        unsigned long n_refs;
-        NDhcp4ClientConfig *config;
-        CList event_list;
-
-        NDhcp4LogQueue log_queue;
-
-        int fd_epoll;
-        int fd_timer;
-
-        uint16_t mtu;
-        NDhcp4ClientProbe *current_probe;
-        uint64_t scheduled_timeout;
-
-        bool preempted : 1;
-};
-
-#define N_DHCP4_CLIENT_NULL(_x) {                                               \
-                .n_refs = 1,                                                    \
-                .event_list = C_LIST_INIT((_x).event_list),                     \
-                .fd_epoll = -1,                                                 \
-                .fd_timer = -1,                                                 \
-                .log_queue = N_DHCP4_LOG_QUEUE_NULL_CLIENT(_x),                 \
-        }
-
-struct NDhcp4ClientProbe {
-        NDhcp4ClientProbeConfig *config;
-        NDhcp4Client *client;
-        CList event_list;
-        CList lease_list;
-        void *userdata;
-
-        unsigned int state;                     /* current probe state */
-        struct in_addr last_address;            /* last address obtained */
-        uint64_t ns_deferred;                   /* timeout for deferred action */
-        uint64_t ns_reinit;
-        uint64_t ns_nak_restart_delay;          /* restart delay after a nak */
-        NDhcp4ClientLease *current_lease;       /* current lease */
-
-        NDhcp4CConnection connection;           /* client connection wrapper */
-};
-
-#define N_DHCP4_CLIENT_PROBE_NULL(_x) {                                         \
-                .event_list = C_LIST_INIT((_x).event_list),                     \
-                .lease_list = C_LIST_INIT((_x).lease_list),                     \
-                .connection = N_DHCP4_C_CONNECTION_NULL((_x).connection),       \
-        }
-
-struct NDhcp4ClientLease {
-        unsigned long n_refs;
-
-        NDhcp4ClientProbe *probe;
-        CList probe_link;
-
-        NDhcp4Incoming *message;
-
-        uint64_t t1;
-        uint64_t t2;
-        uint64_t lifetime;
-};
-
-#define N_DHCP4_CLIENT_LEASE_NULL(_x) {                                         \
-                .n_refs = 1,                                                    \
-                .probe_link = C_LIST_INIT((_x).probe_link),                     \
-        }
-
-struct NDhcp4ServerConfig {
-        int ifindex;
-};
-
-#define N_DHCP4_SERVER_CONFIG_NULL(_x) {                                        \
-        }
-
-struct NDhcp4SEventNode {
-        CList server_link;
-        NDhcp4ServerEvent event;
-        bool is_public : 1;
-};
-
-#define N_DHCP4_S_EVENT_NODE_NULL(_x) {                                         \
-                .server_link = C_LIST_INIT((_x).server_link),                   \
-        }
-
-struct NDhcp4SConnection {
-        int ifindex;                    /* interface index */
-        int fd_packet;                  /* packet socket */
-        int fd_udp;                     /* udp socket */
-        uint8_t buf[UINT16_MAX];        /* scratch recevie buffer */
-
-        /* XXX: support a set of server addresses */
-        NDhcp4SConnectionIp *ip;        /* server IP address, or NULL */
-};
-
-#define N_DHCP4_S_CONNECTION_NULL(_x) {                                         \
-                .fd_packet = -1,                                                \
-                .fd_udp = -1,                                                   \
-        }
-
-struct NDhcp4SConnectionIp {
-        NDhcp4SConnection *connection;
-        struct in_addr ip;
-};
-
-#define N_DHCP4_S_CONNECTION_IP_NULL(_x) {                                      \
-}
-
-struct NDhcp4Server {
-        unsigned long n_refs;
-        CList event_list;
-        CList lease_list;
-
-        bool preempted : 1;
-
-        NDhcp4SConnection connection;
-};
-
-#define N_DHCP4_SERVER_NULL(_x) {                                               \
-                .n_refs = 1,                                                    \
-                .event_list = C_LIST_INIT((_x).event_list),                     \
-                .lease_list = C_LIST_INIT((_x).lease_list),                     \
-                .connection = N_DHCP4_S_CONNECTION_NULL((_x).connection),       \
-        }
-
-struct NDhcp4ServerIp {
-                NDhcp4SConnectionIp ip;
-};
-
-#define N_DHCP4_SERVER_IP_NULL(_x) {                                            \
-                .ip = N_DHCP4_S_CONNECTION_IP_NULL((_x).ip),                    \
-        }
-
-struct NDhcp4ServerLease {
-        unsigned long n_refs;
-
-        NDhcp4Server *server;
-        CList server_link;
-
-        NDhcp4Incoming *request;
-        NDhcp4Incoming *reply;
-};
-
-#define N_DHCP4_SERVER_LEASE_NULL(_x) {                                         \
-                .n_refs = 1,                                                    \
-                .server_link = C_LIST_INIT((_x).server_link),                   \
-        }
-
-/* outgoing messages */
-
-int n_dhcp4_outgoing_new(NDhcp4Outgoing **outgoingp, size_t max_size, uint8_t overload);
-NDhcp4Outgoing *n_dhcp4_outgoing_free(NDhcp4Outgoing *outgoing);
-
-NDhcp4Header *n_dhcp4_outgoing_get_header(NDhcp4Outgoing *outgoing);
-size_t n_dhcp4_outgoing_get_raw(NDhcp4Outgoing *outgoing, const void **rawp);
-int n_dhcp4_outgoing_append(NDhcp4Outgoing *outgoing, uint8_t option, const void *data, uint8_t n_data);
-
-int n_dhcp4_outgoing_append_t1(NDhcp4Outgoing *message, uint32_t t1);
-int n_dhcp4_outgoing_append_t2(NDhcp4Outgoing *message, uint32_t t2);
-int n_dhcp4_outgoing_append_lifetime(NDhcp4Outgoing *message, uint32_t lifetime);
-int n_dhcp4_outgoing_append_server_identifier(NDhcp4Outgoing *message, struct in_addr addr);
-int n_dhcp4_outgoing_append_requested_ip(NDhcp4Outgoing *message, struct in_addr addr);
-
-void n_dhcp4_outgoing_set_secs(NDhcp4Outgoing *message, uint16_t secs);
-void n_dhcp4_outgoing_set_xid(NDhcp4Outgoing *message, uint32_t xid);
-void n_dhcp4_outgoing_set_yiaddr(NDhcp4Outgoing *message, struct in_addr yiaddr);
-
-void n_dhcp4_outgoing_get_xid(NDhcp4Outgoing *message, uint32_t *xidp);
-
-/* incoming messages */
-
-int n_dhcp4_incoming_new(NDhcp4Incoming **incomingp, const void *raw, size_t n_raw);
-NDhcp4Incoming *n_dhcp4_incoming_free(NDhcp4Incoming *incoming);
-
-NDhcp4Header *n_dhcp4_incoming_get_header(NDhcp4Incoming *incoming);
-size_t n_dhcp4_incoming_get_raw(NDhcp4Incoming *incoming, const void **rawp);
-int n_dhcp4_incoming_query(NDhcp4Incoming *incoming, uint8_t option, uint8_t **datap, size_t *n_datap);
-
-int n_dhcp4_incoming_query_message_type(NDhcp4Incoming *message, uint8_t *typep);
-int n_dhcp4_incoming_query_lifetime(NDhcp4Incoming *message, uint32_t *lifetimep);
-int n_dhcp4_incoming_query_t2(NDhcp4Incoming *message, uint32_t *t2p);
-int n_dhcp4_incoming_query_t1(NDhcp4Incoming *message, uint32_t *t1p);
-int n_dhcp4_incoming_query_server_identifier(NDhcp4Incoming *message, struct in_addr *idp);
-int n_dhcp4_incoming_query_max_message_size(NDhcp4Incoming *message, uint16_t *max_message_sizep);
-int n_dhcp4_incoming_query_requested_ip(NDhcp4Incoming *message, struct in_addr *requested_ipp);
-
-void n_dhcp4_incoming_get_xid(NDhcp4Incoming *message, uint32_t *xidp);
-void n_dhcp4_incoming_get_yiaddr(NDhcp4Incoming *message, struct in_addr *yiaddr);
-
-/* sockets */
-
-int n_dhcp4_c_socket_packet_new(int *sockfdp, int ifindex);
-int n_dhcp4_c_socket_udp_new(int *sockfdp,
-                             int ifindex,
-                             const struct in_addr *client_addr,
-                             const struct in_addr *server_addr);
-int n_dhcp4_s_socket_packet_new(int *sockfdp);
-int n_dhcp4_s_socket_udp_new(int *sockfdp, int ifindex);
-
-int n_dhcp4_c_socket_packet_send(int sockfd,
-                                 int ifindex,
-                                 const unsigned char *dest_haddr,
-                                 unsigned char halen,
-                                 NDhcp4Outgoing *message);
-int n_dhcp4_c_socket_udp_send(int sockfd, NDhcp4Outgoing *message);
-int n_dhcp4_c_socket_udp_broadcast(int sockfd, NDhcp4Outgoing *message);
-int n_dhcp4_s_socket_packet_send(int sockfd,
-                                 int ifindex,
-                                 const struct in_addr *src_inaddr,
-                                 const unsigned char *dest_haddr,
-                                 unsigned char halen,
-                                 const struct in_addr *dest_inaddr,
-                                 NDhcp4Outgoing *message);
-int n_dhcp4_s_socket_udp_send(int sockfd,
-                              const struct in_addr *inaddr_src,
-                              const struct in_addr *inaddr_dest,
-                              NDhcp4Outgoing *message);
-int n_dhcp4_s_socket_udp_broadcast(int sockfd,
-                                   const struct in_addr *inaddr_src,
-                                   NDhcp4Outgoing *message);
-
-int n_dhcp4_c_socket_packet_recv(int sockfd,
-                                 uint8_t *buf,
-                                 size_t n_buf,
-                                 NDhcp4Incoming **messagep);
-int n_dhcp4_c_socket_udp_recv(int sockfd,
-                              uint8_t *buf,
-                              size_t n_buf,
-                              NDhcp4Incoming **messagep);
-int n_dhcp4_s_socket_udp_recv(int sockfd,
-                              uint8_t *buf,
-                              size_t n_buf,
-                              NDhcp4Incoming **messagep,
-                              struct sockaddr_in *dest);
-
-/* client configs */
-
-int n_dhcp4_client_config_dup(NDhcp4ClientConfig *config,
-                              NDhcp4ClientConfig **dupp);
-
-/* client probe configs */
-
-int n_dhcp4_client_probe_config_dup(NDhcp4ClientProbeConfig *config,
-                                    NDhcp4ClientProbeConfig **dupp);
-uint32_t n_dhcp4_client_probe_config_get_random(NDhcp4ClientProbeConfig *config);
-
-/* client events */
-
-int n_dhcp4_c_event_node_new(NDhcp4CEventNode **nodep);
-NDhcp4CEventNode *n_dhcp4_c_event_node_free(NDhcp4CEventNode *node);
-
-/* client connections */
-
-int n_dhcp4_c_connection_init(NDhcp4CConnection *connection,
-                              NDhcp4ClientConfig *client_config,
-                              NDhcp4ClientProbeConfig *probe_config,
-                              NDhcp4LogQueue *log_queue,
-                              int fd_epoll);
-void n_dhcp4_c_connection_deinit(NDhcp4CConnection *connection);
-
-int n_dhcp4_c_connection_listen(NDhcp4CConnection *connection);
-int n_dhcp4_c_connection_connect(NDhcp4CConnection *connection,
-                                 const struct in_addr *client,
-                                 const struct in_addr *server);
-void n_dhcp4_c_connection_close(NDhcp4CConnection *connection);
-
-void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection,
-                                      uint64_t *timeoutp);
-
-int n_dhcp4_c_connection_discover_new(NDhcp4CConnection *connection,
-                                      NDhcp4Outgoing **request);
-int n_dhcp4_c_connection_select_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **request,
-                                    NDhcp4Incoming *offer);
-int n_dhcp4_c_connection_reboot_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **request,
-                                    const struct in_addr *client);
-int n_dhcp4_c_connection_renew_new(NDhcp4CConnection *connection,
-                                   NDhcp4Outgoing **request);
-int n_dhcp4_c_connection_rebind_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **request);
-int n_dhcp4_c_connection_decline_new(NDhcp4CConnection *connection,
-                                     NDhcp4Outgoing **request,
-                                     NDhcp4Incoming *ack,
-                                     const char *error);
-int n_dhcp4_c_connection_inform_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **request);
-int n_dhcp4_c_connection_release_new(NDhcp4CConnection *connection,
-                                     NDhcp4Outgoing **request,
-                                     const char *error);
-
-int n_dhcp4_c_connection_start_request(NDhcp4CConnection *connection,
-                                       NDhcp4Outgoing *request,
-                                       uint64_t timestamp);
-int n_dhcp4_c_connection_dispatch_timer(NDhcp4CConnection *connection,
-                                        uint64_t timestamp);
-int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
-                                     NDhcp4Incoming **messagep);
-
-/* clients */
-
-int n_dhcp4_client_raise(NDhcp4Client *client, NDhcp4CEventNode **nodep, unsigned int event);
-void n_dhcp4_client_arm_timer(NDhcp4Client *client);
-
-/* client probes */
-
-int n_dhcp4_client_probe_new(NDhcp4ClientProbe **probep,
-                             NDhcp4ClientProbeConfig *config,
-                             NDhcp4Client *client,
-                             uint64_t ns_now);
-
-int n_dhcp4_client_probe_raise(NDhcp4ClientProbe *probe, NDhcp4CEventNode **nodep, unsigned int event);
-void n_dhcp4_client_probe_get_timeout(NDhcp4ClientProbe *probe, uint64_t *timeoutp);
-int n_dhcp4_client_probe_dispatch_timer(NDhcp4ClientProbe *probe, uint64_t ns_now);
-int n_dhcp4_client_probe_dispatch_io(NDhcp4ClientProbe *probe, uint32_t events);
-int n_dhcp4_client_probe_transition_select(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, uint64_t ns_now);
-int n_dhcp4_client_probe_transition_accept(NDhcp4ClientProbe *probe, NDhcp4Incoming *ack);
-int n_dhcp4_client_probe_transition_decline(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, const char *error, uint64_t ns_now);
-int n_dhcp4_client_probe_update_mtu(NDhcp4ClientProbe *probe, uint16_t mtu);
-
-/* client leases */
-
-int n_dhcp4_client_lease_new(NDhcp4ClientLease **leasep, NDhcp4Incoming *message);
-void n_dhcp4_client_lease_link(NDhcp4ClientLease *lease, NDhcp4ClientProbe *probe);
-void n_dhcp4_client_lease_unlink(NDhcp4ClientLease *lease);
-
-/* server connections */
-
-int n_dhcp4_s_connection_init(NDhcp4SConnection *connection, int ifindex);
-void n_dhcp4_s_connection_deinit(NDhcp4SConnection *connection);
-
-void n_dhcp4_s_connection_get_fd(NDhcp4SConnection *connection, int *fdp);
-int n_dhcp4_s_connection_dispatch_io(NDhcp4SConnection *connection, NDhcp4Incoming **messagep);
-
-int n_dhcp4_s_connection_offer_new(NDhcp4SConnection *connection,
-                                   NDhcp4Outgoing **replyp,
-                                   NDhcp4Incoming *request,
-                                   const struct in_addr *server_address,
-                                   const struct in_addr *client_address,
-                                   uint32_t lifetime);
-int n_dhcp4_s_connection_ack_new(NDhcp4SConnection *connection,
-                                   NDhcp4Outgoing **replyp,
-                                   NDhcp4Incoming *request,
-                                   const struct in_addr *server_address,
-                                   const struct in_addr *client_address,
-                                   uint32_t lifetime);
-int n_dhcp4_s_connection_nak_new(NDhcp4SConnection *connection,
-                                 NDhcp4Outgoing **replyp,
-                                 NDhcp4Incoming *request,
-                                 const struct in_addr *server_address);
-
-int n_dhcp4_s_connection_send_reply(NDhcp4SConnection *connection,
-                                    const struct in_addr *server_addr,
-                                    NDhcp4Outgoing *reply);
-
-/* server connection ips */
-
-void n_dhcp4_s_connection_ip_init(NDhcp4SConnectionIp *ip, struct in_addr addr);
-void n_dhcp4_s_connection_ip_deinit(NDhcp4SConnectionIp *ip);
-
-void n_dhcp4_s_connection_ip_link(NDhcp4SConnectionIp *ip, NDhcp4SConnection *connection);
-void n_dhcp4_s_connection_ip_unlink(NDhcp4SConnectionIp *ip);
-
-/* inline helpers */
-
-static inline void n_dhcp4_outgoing_freep(NDhcp4Outgoing **outgoing) {
-        if (*outgoing)
-                n_dhcp4_outgoing_free(*outgoing);
-}
-
-static inline void n_dhcp4_incoming_freep(NDhcp4Incoming **incoming) {
-        if (*incoming)
-                n_dhcp4_incoming_free(*incoming);
-}
-
-static inline uint64_t n_dhcp4_gettime(clockid_t clock) {
-        struct timespec ts;
-        int r;
-
-        r = clock_gettime(clock, &ts);
-        c_assert(r >= 0);
-
-        return ts.tv_sec * 1000ULL * 1000ULL * 1000ULL + ts.tv_nsec;
-}
-
-void n_dhcp4_log_queue_fmt(NDhcp4LogQueue *log_queue,
-                           int level,
-                           const char *fmt,
-                           ...) _c_printf_(3, 4);
-
-/**
- * n_dhcp4_log() - append a logging event
- * @x_log_queue:   the logging event queue
- * @x_level:       the syslog logging level for the message.
- * @...:           the format string and arguments.
- *
- * Warning: this macro only evaluates the format arguments if the logging
- * level is enabled.
- */
-#define n_dhcp4_log(x_log_queue, x_level, ...)                                 \
-        do {                                                                   \
-                NDhcp4LogQueue *const _log_queue = (x_log_queue);              \
-                const int _level = (x_level);                                  \
-                                                                               \
-                if (_level <= _log_queue->log_level) {                         \
-                        n_dhcp4_log_queue_fmt(_log_queue,                      \
-                                              _level,                          \
-                                              __VA_ARGS__);                    \
-                }                                                              \
-        } while (0)
diff --git a/shared/n-dhcp4/src/n-dhcp4-socket.c b/shared/n-dhcp4/src/n-dhcp4-socket.c
deleted file mode 100644
index 3e703b4f..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-socket.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * DHCP specific low-level socket helpers
- */
-
-#include <c-stdaux.h>
-#include <errno.h>
-#include <linux/filter.h>
-#include <sys/socket.h> /* needed by linux/if.h */
-#include <linux/if.h>
-#include <linux/if_packet.h>
-#include <linux/netdevice.h>
-#include <linux/udp.h>
-#include <netinet/ip.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/types.h>
-#include "n-dhcp4-private.h"
-#include "util/packet.h"
-#include "util/socket.h"
-
-/**
- * n_dhcp4_c_socket_packet_new() - create a new DHCP4 client packet socket
- * @sockfdp:            return argument for the new socket
- * @ifindex:            interface index to bind to
- *
- * Create a new AF_PACKET/SOCK_DGRAM socket usable to listen to and send DHCP client
- * packets before an IP address has been configured.
- *
- * Only unfragmented DHCP packets from a server to a client destined for the given
- * ifindex is returned.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int n_dhcp4_c_socket_packet_new(int *sockfdp, int ifindex) {
-        _c_cleanup_(c_closep) int sockfd = -1;
-        struct sock_filter filter[] = {
-                /*
-                 * IP
-                 *
-                 * Check
-                 *  - UDP
-                 *  - Unfragmented
-                 *  - Large enough to fit the DHCP header
-                 *
-                 *  Leave X the size of the IP header, for future indirect reads.
-                 */
-                BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct iphdr, protocol)),                           /* A <- IP protocol */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0),                                         /* IP protocol == UDP ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct iphdr, frag_off)),                           /* A <- Flags + Fragment offset */
-                BPF_STMT(BPF_ALU + BPF_AND + BPF_K, IP_MF | IP_OFFMASK),                                        /* A <- A & (IP_MF | IP_OFFMASK) */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                                                   /* fragmented packet ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 0),                                                         /* X <- IP header length */
-                BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0),                                                          /* A <- packet length */
-                BPF_STMT(BPF_ALU + BPF_SUB + BPF_X, 0),                                                         /* A -= X */
-                BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct udphdr) + sizeof(NDhcp4Message), 1, 0),       /* packet >= DHCPPacket ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                /*
-                 * UDP
-                 *
-                 * Check
-                 *  - DHCP client port
-                 *
-                 * Leave X the size of IP and UDP headers, for future indirect reads.
-                 */
-                BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct udphdr, dest)),                              /* A <- UDP destination port */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_NETWORK_CLIENT_PORT, 1, 0),                         /* UDP destination port == DHCP client port ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LD + BPF_W + BPF_K, sizeof(struct udphdr)),                                        /* A <- size of UDP header */
-                BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),                                                         /* A += X */
-                BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                                /* X <- A */
-
-                /*
-                 * DHCP
-                 *
-                 * Check
-                 *  - BOOTREPLY (from server to client)
-                 *  - DHCP magic cookie
-                 */
-                BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(NDhcp4Header, op)),                                 /* A <- DHCP op */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_OP_BOOTREPLY, 1, 0),                                /* op == BOOTREPLY ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LD + BPF_W + BPF_IND, offsetof(NDhcp4Message, magic)),                             /* A <- DHCP magic cookie */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_MESSAGE_MAGIC, 1, 0),                               /* cookie == DHCP magic cookie ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_RET + BPF_K, 65535),                                                               /* return all */
-        };
-        struct sock_fprog fprog = {
-                .filter = filter,
-                .len = sizeof(filter) / sizeof(filter[0]),
-        };
-        struct sockaddr_ll addr = {
-                .sll_family = AF_PACKET,
-                .sll_protocol = htons(ETH_P_IP),
-                .sll_ifindex = ifindex,
-        };
-        int r, on = 1;
-
-        sockfd = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
-        if (sockfd < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
-        if (r < 0)
-                return -errno;
-
-        /* We need the flag that tells us if the checksum is correct. */
-        r = setsockopt(sockfd, SOL_PACKET, PACKET_AUXDATA, &on, sizeof(on));
-        if (r < 0)
-                return -errno;
-
-        r = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
-        if (r < 0)
-                return -errno;
-
-        *sockfdp = sockfd;
-        sockfd = -1;
-        return 0;
-}
-
-/**
- * n_dhcp4_c_socket_udp_new() - create a new DHCP4 client UDP socket
- * @sockfdp:            return argument for the new socket
- * @ifindex:            interface index to bind to
- * @client_addr:        client address to bind to
- * @server_addr:        server address to connect to
- *
- * Create a new AF_INET/SOCK_DGRAM socket usable to listen to and send DHCP client
- * packets.
- *
- * The client address given in @addr must be configured on the interface @ifindex
- * before the socket is created.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int n_dhcp4_c_socket_udp_new(int *sockfdp,
-                             int ifindex,
-                             const struct in_addr *client_addr,
-                             const struct in_addr *server_addr) {
-        _c_cleanup_(c_closep) int sockfd = -1;
-        struct sock_filter filter[] = {
-                /*
-                 * IP/UDP
-                 *
-                 * Set X to the size of IP and UDP headers, for future indirect reads.
-                 */
-                BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 0),                                                         /* X <- IP header length */
-                BPF_STMT(BPF_LD + BPF_W + BPF_K, sizeof(struct udphdr)),                                        /* A <- size of UDP header */
-                BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),                                                         /* A += X */
-                BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                                /* X <- A */
-
-                /*
-                 * DHCP
-                 *
-                 * Check
-                 *  - BOOTREPLY (from server to client)
-                 *  - DHCP magic cookie
-                 */
-                BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(NDhcp4Header, op)),                                 /* A <- DHCP op */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_OP_BOOTREPLY, 1, 0),                                /* op == BOOTREPLY ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LD + BPF_W + BPF_IND, offsetof(NDhcp4Message, magic)),                             /* A <- DHCP magic cookie */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_MESSAGE_MAGIC, 1, 0),                               /* cookie == DHCP magic cookie ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_RET + BPF_K, 65535),                                                               /* return all */
-        };
-        struct sock_fprog fprog = {
-                .filter = filter,
-                .len = sizeof(filter) / sizeof(filter[0]),
-        };
-        struct sockaddr_in saddr = {
-                .sin_family = AF_INET,
-                .sin_addr = *client_addr,
-                .sin_port = htons(N_DHCP4_NETWORK_CLIENT_PORT),
-        };
-        struct sockaddr_in daddr = {
-                .sin_family = AF_INET,
-                .sin_addr = *server_addr,
-                .sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT),
-        };
-        int r, tos = IPTOS_CLASS_CS6, on = 1;
-
-        sockfd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
-        if (sockfd < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-        if (r < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
-        if (r < 0)
-                return -errno;
-
-        r = socket_bind_if(sockfd, ifindex);
-        if (r)
-                return r;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
-        if (r < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
-        if (r < 0)
-                return -errno;
-
-        r = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
-        if (r < 0)
-                return -errno;
-
-        r = connect(sockfd, (struct sockaddr*)&daddr, sizeof(daddr));
-        if (r < 0)
-                return -errno;
-
-        *sockfdp = sockfd;
-        sockfd = -1;
-        return 0;
-}
-
-/**
- * n_dhcp4_s_socket_packet_new() - create a new DHCP4 server packet socket
- * @sockfdp:            return argument for the new socket
- *
- * Create a new AF_PACKET/SOCK_DGRAM socket usable to send DHCP packets to clients
- * before they have an IP address configured, on the given interface.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int n_dhcp4_s_socket_packet_new(int *sockfdp) {
-        _c_cleanup_(c_closep) int sockfd = -1;
-
-        sockfd = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
-        if (sockfd < 0)
-                return -errno;
-
-        *sockfdp = sockfd;
-        sockfd = -1;
-        return 0;
-}
-
-/**
- * n_dhcp4_s_socket_udp_new() - create a new DHCP4 server UDP socket
- * @sockfdp:            return argument for the new socket
- * @ifindex:            intercafe index to bind to
- *
- * Create a new AF_INET/SOCK_DGRAM socket usable to listen to DHCP server packets,
- * on the given interface.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int n_dhcp4_s_socket_udp_new(int *sockfdp, int ifindex) {
-        _c_cleanup_(c_closep) int sockfd = -1;
-        struct sock_filter filter[] = {
-                /*
-                 * IP/UDP
-                 *
-                 * Set X to the size of IP and UDP headers, for future indirect reads.
-                 */
-                BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 0),                                                         /* X <- IP header length */
-                BPF_STMT(BPF_LD + BPF_W + BPF_K, sizeof(struct udphdr)),                                        /* A <- size of UDP header */
-                BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),                                                         /* A += X */
-                BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                                /* X <- A */
-
-                /*
-                 * DHCP
-                 *
-                 * Check
-                 *  - BOOTREQUEST (from client to server)
-                 *  - DHCP magic cookie
-                 */
-
-                BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(NDhcp4Header, op)),                                 /* A <- DHCP op */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_OP_BOOTREQUEST, 1, 0),                              /* op == BOOTREQUEST ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LD + BPF_W + BPF_IND, offsetof(NDhcp4Message, magic)),                             /* A <- DHCP magic cookie */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_MESSAGE_MAGIC, 1, 0),                               /* cookie == DHCP magic cookie ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_RET + BPF_K, 65535),                                                               /* return all */
-        };
-        struct sock_fprog fprog = {
-                .filter = filter,
-                .len = sizeof(filter) / sizeof(filter[0]),
-        };
-        struct sockaddr_in addr = {
-                .sin_family = AF_INET,
-                .sin_addr = { INADDR_ANY },
-                .sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT),
-        };
-        int r, tos = IPTOS_CLASS_CS6, on = 1;
-
-        sockfd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
-        if (sockfd < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
-        if (r < 0)
-                return -errno;
-
-        r = socket_bind_if(sockfd, ifindex);
-        if (r)
-                return r;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
-        if (r < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
-        if (r < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
-        if (r < 0)
-                return -errno;
-
-        r = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
-        if (r < 0)
-                return -errno;
-
-        *sockfdp = sockfd;
-        sockfd = -1;
-        return 0;
-}
-
-static int n_dhcp4_socket_packet_send(int sockfd,
-                                      int ifindex,
-                                      const struct sockaddr_in *src_paddr,
-                                      const unsigned char *dest_haddr,
-                                      unsigned char halen,
-                                      const struct sockaddr_in *dest_paddr,
-                                      NDhcp4Outgoing *message) {
-        struct packet_sockaddr_ll haddr = {
-                .sll_family = AF_PACKET,
-                .sll_protocol = htons(ETH_P_IP),
-                .sll_ifindex = ifindex,
-                .sll_halen = halen,
-        };
-        const void *buf;
-        size_t n_buf, len;
-        int r;
-
-        c_assert(halen <= sizeof(haddr.sll_addr));
-
-        memcpy(haddr.sll_addr, dest_haddr, halen);
-
-        n_buf = n_dhcp4_outgoing_get_raw(message, &buf);
-
-        r = packet_sendto_udp(sockfd, buf, n_buf, &len, src_paddr, &haddr, dest_paddr);
-        if (r < 0) {
-                if (r == -EAGAIN || r == -ENOBUFS)
-                        return N_DHCP4_E_DROPPED;
-                else if (r == -ENETDOWN || r == -ENXIO)
-                        return N_DHCP4_E_DOWN;
-                else
-                        return r;
-        } else if (len != n_buf) {
-                return N_DHCP4_E_DROPPED;
-        }
-
-        return 0;
-}
-
-/**
- * n_dhcp4_c_socket_packet_send() - XXX
- */
-int n_dhcp4_c_socket_packet_send(int sockfd,
-                                 int ifindex,
-                                 const unsigned char *dest_haddr,
-                                 unsigned char halen,
-                                 NDhcp4Outgoing *message) {
-        struct sockaddr_in src_paddr = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_CLIENT_PORT),
-                .sin_addr = { INADDR_ANY },
-        };
-        struct sockaddr_in dest_paddr = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT),
-                .sin_addr = { INADDR_BROADCAST }
-        };
-
-        return n_dhcp4_socket_packet_send(sockfd,
-                                          ifindex,
-                                          &src_paddr,
-                                          dest_haddr,
-                                          halen,
-                                          &dest_paddr,
-                                          message);
-}
-
-/**
- * n_dhcp4_c_socket_udp_send() - XXX
- */
-int n_dhcp4_c_socket_udp_send(int sockfd,
-                              NDhcp4Outgoing *message) {
-        const void *buf;
-        size_t n_buf;
-        ssize_t len;
-
-        n_buf = n_dhcp4_outgoing_get_raw(message, &buf);
-
-        len = send(sockfd, buf, n_buf, 0);
-        if (len < 0) {
-                if (errno == EAGAIN || errno == ENOBUFS)
-                        return N_DHCP4_E_DROPPED;
-                else if (errno == ENETDOWN || errno == ENXIO)
-                        return N_DHCP4_E_DOWN;
-                else
-                        return -errno;
-        } else if ((size_t)len != n_buf)
-                return N_DHCP4_E_DROPPED;
-
-        return 0;
-}
-
-/**
- * n_dhcp4_c_socket_udp_broadcast() - XXX
- */
-int n_dhcp4_c_socket_udp_broadcast(int sockfd, NDhcp4Outgoing *message) {
-        struct sockaddr_in sockaddr_dest = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT),
-                .sin_addr = { INADDR_BROADCAST },
-        };
-        const void *buf;
-        size_t n_buf;
-        ssize_t len;
-
-        n_buf = n_dhcp4_outgoing_get_raw(message, &buf);
-
-        len = sendto(sockfd,
-                     buf,
-                     n_buf,
-                     0,
-                     (struct sockaddr*)&sockaddr_dest,
-                     sizeof(sockaddr_dest));
-        if (len < 0) {
-                if (errno == EAGAIN || errno == ENOBUFS)
-                        return N_DHCP4_E_DROPPED;
-                else if (errno == ENETDOWN || errno == ENXIO)
-                        return N_DHCP4_E_DOWN;
-                else
-                        return -errno;
-        } else if ((size_t)len != n_buf)
-                return N_DHCP4_E_DROPPED;
-
-        return 0;
-}
-
-/**
- * n_dhcp4_s_socket_packet_send() - XXX
- */
-int n_dhcp4_s_socket_packet_send(int sockfd,
-                                 int ifindex,
-                                 const struct in_addr *src_inaddr,
-                                 const unsigned char *dest_haddr,
-                                 unsigned char halen,
-                                 const struct in_addr *dest_inaddr,
-                                 NDhcp4Outgoing *message) {
-        struct sockaddr_in src_paddr = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT),
-                .sin_addr = *src_inaddr,
-        };
-        struct sockaddr_in dest_paddr = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_CLIENT_PORT),
-                .sin_addr = *dest_inaddr,
-        };
-
-        return n_dhcp4_socket_packet_send(sockfd,
-                                          ifindex,
-                                          &src_paddr,
-                                          dest_haddr,
-                                          halen,
-                                          &dest_paddr,
-                                          message);
-}
-
-/**
- * n_dhcp4_s_socket_udp_send() - XXX
- */
-int n_dhcp4_s_socket_udp_send(int sockfd,
-                              const struct in_addr *inaddr_src,
-                              const struct in_addr *inaddr_dest,
-                              NDhcp4Outgoing *message) {
-        struct sockaddr_in sockaddr_dest = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_CLIENT_PORT),
-                .sin_addr = *inaddr_dest,
-        };
-        struct iovec iov = {};
-        union {
-               struct cmsghdr align; /* ensure correct stack alignment */
-               char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
-        } control = {};
-        struct in_pktinfo pktinfo = {
-                .ipi_spec_dst = *inaddr_src,
-        };
-        struct msghdr msg = {
-                .msg_name = (void*)&sockaddr_dest,
-                .msg_namelen = sizeof(sockaddr_dest),
-                .msg_iov = &iov,
-                .msg_iovlen = 1,
-                .msg_control = &control.buf,
-                .msg_controllen = sizeof(control.buf),
-        };
-        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
-        ssize_t len;
-
-        cmsg->cmsg_level = IPPROTO_IP;
-        cmsg->cmsg_type = IP_PKTINFO;
-        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
-        memcpy(CMSG_DATA(cmsg), &pktinfo, sizeof(pktinfo));
-
-        iov.iov_len = n_dhcp4_outgoing_get_raw(message, (const void **)&iov.iov_base);
-
-        len = sendmsg(sockfd, &msg, 0);
-        if (len < 0) {
-                if (errno == EAGAIN || errno == ENOBUFS)
-                        return N_DHCP4_E_DROPPED;
-                else if (errno == ENETDOWN || errno == ENXIO)
-                        return N_DHCP4_E_DOWN;
-                else
-                        return -errno;
-        } else if ((size_t)len != iov.iov_len)
-                return N_DHCP4_E_DROPPED;
-
-        return 0;
-}
-
-int n_dhcp4_s_socket_udp_broadcast(int sockfd,
-                                   const struct in_addr *inaddr_src,
-                                   NDhcp4Outgoing *message) {
-        return n_dhcp4_s_socket_udp_send(sockfd,
-                                         inaddr_src,
-                                         &(const struct in_addr){INADDR_BROADCAST},
-                                         message);
-}
-
-int n_dhcp4_c_socket_packet_recv(int sockfd,
-                                 uint8_t *buf,
-                                 size_t n_buf,
-                                 NDhcp4Incoming **messagep) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = NULL;
-        size_t len;
-        int r;
-
-        r = packet_recv_udp(sockfd, buf, n_buf, &len);
-        if (r < 0) {
-                if (r == -ENETDOWN)
-                        return N_DHCP4_E_DOWN;
-                else if (r == -EAGAIN)
-                        return N_DHCP4_E_AGAIN;
-                else
-                        return -errno;
-        } else if (len == 0) {
-                return N_DHCP4_E_MALFORMED;
-        }
-
-        r = n_dhcp4_incoming_new(&message, buf, len);
-        if (r)
-                return r;
-
-        *messagep = message;
-        message = NULL;
-        return 0;
-}
-
-static int n_dhcp4_socket_udp_recv(int sockfd,
-                                   uint8_t *buf,
-                                   size_t n_buf,
-                                   NDhcp4Incoming **messagep,
-                                   struct in_pktinfo *pktinfo) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = NULL;
-        struct iovec iov = {
-                .iov_base = buf,
-                .iov_len = n_buf,
-        };
-        uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
-        struct msghdr msg = {
-                .msg_iov = &iov,
-                .msg_iovlen = 1,
-                .msg_control = cmsgbuf,
-                .msg_controllen = sizeof(cmsgbuf),
-        };
-        ssize_t len;
-        int r;
-
-        len = recvmsg(sockfd, &msg, MSG_TRUNC);
-        if (len < 0) {
-                if (errno == ENETDOWN)
-                        return N_DHCP4_E_DOWN;
-                else if (errno == EAGAIN)
-                        return N_DHCP4_E_AGAIN;
-                else
-                        return -errno;
-        } else if (len == 0 || (size_t)len > n_buf) {
-                return N_DHCP4_E_MALFORMED;
-        }
-
-        r = n_dhcp4_incoming_new(&message, buf, len);
-        if (r)
-                return r;
-
-        if (pktinfo) {
-                struct cmsghdr *cmsg;
-
-                cmsg = CMSG_FIRSTHDR(&msg);
-                c_assert(cmsg);
-                c_assert(cmsg->cmsg_level == IPPROTO_IP);
-                c_assert(cmsg->cmsg_type == IP_PKTINFO);
-                c_assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo)));
-
-                memcpy(pktinfo, (void*)CMSG_DATA(cmsg), sizeof(struct in_pktinfo));
-        }
-
-        *messagep = message;
-        message = NULL;
-        return 0;
-}
-
-int n_dhcp4_c_socket_udp_recv(int sockfd,
-                              uint8_t *buf,
-                              size_t n_buf,
-                              NDhcp4Incoming **messagep) {
-        return n_dhcp4_socket_udp_recv(sockfd, buf, n_buf, messagep, NULL);
-}
-
-int n_dhcp4_s_socket_udp_recv(int sockfd,
-                              uint8_t *buf,
-                              size_t n_buf,
-                              NDhcp4Incoming **messagep,
-                              struct sockaddr_in *dest) {
-        struct in_pktinfo pktinfo = {};
-        int r;
-
-        r = n_dhcp4_socket_udp_recv(sockfd, buf, n_buf, messagep, &pktinfo);
-        if (r)
-                return r;
-
-        if (dest) {
-                dest->sin_family = AF_INET;
-                dest->sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT);
-                dest->sin_addr.s_addr = pktinfo.ipi_addr.s_addr;
-        }
-
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4.h b/shared/n-dhcp4/src/n-dhcp4.h
deleted file mode 100644
index 435c5600..00000000
--- a/shared/n-dhcp4/src/n-dhcp4.h
+++ /dev/null
@@ -1,300 +0,0 @@
-#pragma once
-
-/*
- * Dynamic Host Configuration Protocol for IPv4
- *
- * This is the public header of the n-dhcp4 library, implementing IPv4 Dynamic
- * Host Configuration Protocol as described in RFC-2132. This header defines
- * the public API and all entry points of n-dhcp4.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <inttypes.h>
-#include <netinet/in.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-typedef struct NDhcp4Client NDhcp4Client;
-typedef struct NDhcp4ClientConfig NDhcp4ClientConfig;
-typedef struct NDhcp4ClientEvent NDhcp4ClientEvent;
-typedef struct NDhcp4ClientLease NDhcp4ClientLease;
-typedef struct NDhcp4ClientProbe NDhcp4ClientProbe;
-typedef struct NDhcp4ClientProbeConfig NDhcp4ClientProbeConfig;
-typedef struct NDhcp4Server NDhcp4Server;
-typedef struct NDhcp4ServerConfig NDhcp4ServerConfig;
-typedef struct NDhcp4ServerEvent NDhcp4ServerEvent;
-typedef struct NDhcp4ServerIp NDhcp4ServerIp;
-typedef struct NDhcp4ServerLease NDhcp4ServerLease;
-
-#define N_DHCP4_CLIENT_START_DELAY_RFC2131 (UINT64_C(9000))
-
-enum {
-        _N_DHCP4_E_SUCCESS,
-
-        N_DHCP4_E_PREEMPTED,
-        N_DHCP4_E_INTERNAL,
-
-        N_DHCP4_E_INVALID_IFINDEX,
-        N_DHCP4_E_INVALID_TRANSPORT,
-        N_DHCP4_E_INVALID_ADDRESS,
-        N_DHCP4_E_INVALID_CLIENT_ID,
-        N_DHCP4_E_DUPLICATE_OPTION,
-        N_DHCP4_E_UNSET,
-
-        _N_DHCP4_E_N,
-};
-
-enum {
-        N_DHCP4_TRANSPORT_ETHERNET,
-        N_DHCP4_TRANSPORT_INFINIBAND,
-        _N_DHCP4_TRANSPORT_N,
-};
-
-enum {
-        N_DHCP4_CLIENT_EVENT_DOWN,
-        N_DHCP4_CLIENT_EVENT_OFFER,
-        N_DHCP4_CLIENT_EVENT_GRANTED,
-        N_DHCP4_CLIENT_EVENT_RETRACTED,
-        N_DHCP4_CLIENT_EVENT_EXTENDED,
-        N_DHCP4_CLIENT_EVENT_EXPIRED,
-        N_DHCP4_CLIENT_EVENT_CANCELLED,
-        N_DHCP4_CLIENT_EVENT_LOG,
-        _N_DHCP4_CLIENT_EVENT_N,
-};
-
-enum {
-        N_DHCP4_SERVER_EVENT_DOWN,
-        N_DHCP4_SERVER_EVENT_DISCOVER,
-        N_DHCP4_SERVER_EVENT_REQUEST,
-        N_DHCP4_SERVER_EVENT_RENEW,
-        N_DHCP4_SERVER_EVENT_DECLINE,
-        N_DHCP4_SERVER_EVENT_RELEASE,
-        _N_DHCP4_SERVER_EVENT_N,
-};
-
-struct NDhcp4ClientEvent {
-        unsigned int event;
-        union {
-                struct {
-                } down;
-                struct {
-                        NDhcp4ClientProbe *probe;
-                        NDhcp4ClientLease *lease;
-                } offer, granted, extended;
-                struct {
-                        NDhcp4ClientProbe *probe;
-                } retracted, expired, cancelled;
-                struct {
-                        /* If allow_steal_message is true, then the user may steal the message when handling
-                         * the event. In that case, set the message field to %NULL and free it yourself
-                         * with free(). */
-                        const char *message;
-                        int level;
-                        bool allow_steal_message;
-                } log;
-        };
-};
-
-struct NDhcp4ServerEvent {
-        unsigned int event;
-        union {
-                struct {
-                } down;
-                struct {
-                        NDhcp4ServerLease *lease;
-                } discover, request, decline, release;
-        };
-};
-
-/* client configs */
-
-int n_dhcp4_client_config_new(NDhcp4ClientConfig **configp);
-NDhcp4ClientConfig *n_dhcp4_client_config_free(NDhcp4ClientConfig *config);
-
-void n_dhcp4_client_config_set_ifindex(NDhcp4ClientConfig *config, int ifindex);
-void n_dhcp4_client_config_set_transport(NDhcp4ClientConfig *config, unsigned int transport);
-void n_dhcp4_client_config_set_request_broadcast(NDhcp4ClientConfig *config, bool request_broadcast);
-void n_dhcp4_client_config_set_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac);
-void n_dhcp4_client_config_set_broadcast_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac);
-int n_dhcp4_client_config_set_client_id(NDhcp4ClientConfig *config, const uint8_t *id, size_t n_id);
-
-/* client-probe configs */
-
-int n_dhcp4_client_probe_config_new(NDhcp4ClientProbeConfig **configp);
-NDhcp4ClientProbeConfig *n_dhcp4_client_probe_config_free(NDhcp4ClientProbeConfig *config);
-
-void n_dhcp4_client_probe_config_set_inform_only(NDhcp4ClientProbeConfig *config, bool inform_only);
-void n_dhcp4_client_probe_config_set_init_reboot(NDhcp4ClientProbeConfig *config, bool init_reboot);
-void n_dhcp4_client_probe_config_set_requested_ip(NDhcp4ClientProbeConfig *config, struct in_addr ip);
-void n_dhcp4_client_probe_config_set_start_delay(NDhcp4ClientProbeConfig *config, uint64_t msecs);
-void n_dhcp4_client_probe_config_request_option(NDhcp4ClientProbeConfig *config, uint8_t option);
-int n_dhcp4_client_probe_config_append_option(NDhcp4ClientProbeConfig *config,
-                                              uint8_t option,
-                                              const void *data,
-                                              uint8_t n_data);
-
-/* clients */
-
-int n_dhcp4_client_new(NDhcp4Client **clientp, NDhcp4ClientConfig *config);
-NDhcp4Client *n_dhcp4_client_ref(NDhcp4Client *client);
-NDhcp4Client *n_dhcp4_client_unref(NDhcp4Client *client);
-
-void n_dhcp4_client_get_fd(NDhcp4Client *client, int *fdp);
-int n_dhcp4_client_dispatch(NDhcp4Client *client);
-int n_dhcp4_client_pop_event(NDhcp4Client *client, NDhcp4ClientEvent **eventp);
-
-void n_dhcp4_client_set_log_level(NDhcp4Client *client, int level);
-
-int n_dhcp4_client_update_mtu(NDhcp4Client *client, uint16_t mtu);
-
-int n_dhcp4_client_probe(NDhcp4Client *client,
-                         NDhcp4ClientProbe **probep,
-                         NDhcp4ClientProbeConfig *config);
-
-/* client probes */
-
-NDhcp4ClientProbe *n_dhcp4_client_probe_free(NDhcp4ClientProbe *probe);
-
-void n_dhcp4_client_probe_set_userdata(NDhcp4ClientProbe *probe, void *userdata);
-void n_dhcp4_client_probe_get_userdata(NDhcp4ClientProbe *probe, void **userdatap);
-
-/* client leases */
-
-NDhcp4ClientLease *n_dhcp4_client_lease_ref(NDhcp4ClientLease *lease);
-NDhcp4ClientLease *n_dhcp4_client_lease_unref(NDhcp4ClientLease *lease);
-
-void n_dhcp4_client_lease_get_yiaddr(NDhcp4ClientLease *lease, struct in_addr *yiaddr);
-void n_dhcp4_client_lease_get_siaddr(NDhcp4ClientLease *lease, struct in_addr *siaddr);
-void n_dhcp4_client_lease_get_basetime(NDhcp4ClientLease *lease, uint64_t *ns_basetimep);
-void n_dhcp4_client_lease_get_lifetime(NDhcp4ClientLease *lease, uint64_t *ns_lifetimep);
-int n_dhcp4_client_lease_query(NDhcp4ClientLease *lease, uint8_t option, uint8_t **datap, size_t *n_datap);
-int n_dhcp4_client_lease_get_server_identifier (NDhcp4ClientLease *lease, struct in_addr *addr);
-
-int n_dhcp4_client_lease_select(NDhcp4ClientLease *lease);
-int n_dhcp4_client_lease_accept(NDhcp4ClientLease *lease);
-int n_dhcp4_client_lease_decline(NDhcp4ClientLease *lease, const char *error);
-
-/* server configs */
-
-int n_dhcp4_server_config_new(NDhcp4ServerConfig **configp);
-NDhcp4ServerConfig *n_dhcp4_server_config_free(NDhcp4ServerConfig *config);
-
-void n_dhcp4_server_config_set_ifindex(NDhcp4ServerConfig *config, int ifindex);
-
-/* servers */
-
-int n_dhcp4_server_new(NDhcp4Server **serverp, NDhcp4ServerConfig *config);
-NDhcp4Server *n_dhcp4_server_ref(NDhcp4Server *server);
-NDhcp4Server *n_dhcp4_server_unref(NDhcp4Server *server);
-
-void n_dhcp4_server_get_fd(NDhcp4Server *server, int *fdp);
-int n_dhcp4_server_dispatch(NDhcp4Server *server);
-int n_dhcp4_server_pop_event(NDhcp4Server *server, NDhcp4ServerEvent **eventp);
-
-int n_dhcp4_server_add_ip(NDhcp4Server *server, NDhcp4ServerIp **ipp, struct in_addr ip);
-
-/* server ip addresses */
-
-NDhcp4ServerIp *n_dhcp4_server_ip_free(NDhcp4ServerIp *ip);
-
-/* server leases */
-
-NDhcp4ServerLease *n_dhcp4_server_lease_ref(NDhcp4ServerLease *lease);
-NDhcp4ServerLease *n_dhcp4_server_lease_unref(NDhcp4ServerLease *lease);
-
-int n_dhcp4_server_lease_query(NDhcp4ServerLease *lease, uint8_t option, uint8_t **datap, size_t *n_datap);
-int n_dhcp4_server_lease_append(NDhcp4ServerLease *lease, uint8_t option, uint8_t *data, size_t n_data);
-
-int n_dhcp4_server_lease_offer(NDhcp4ServerLease *lease);
-int n_dhcp4_server_lease_ack(NDhcp4ServerLease *lease);
-int n_dhcp4_server_lease_nack(NDhcp4ServerLease *lease);
-
-/* inline helpers */
-
-static inline void n_dhcp4_client_config_freep(NDhcp4ClientConfig **p) {
-        if (*p)
-                n_dhcp4_client_config_free(*p);
-}
-
-static inline void n_dhcp4_client_config_freev(NDhcp4ClientConfig *p) {
-        n_dhcp4_client_config_free(p);
-}
-
-static inline void n_dhcp4_client_probe_config_freep(NDhcp4ClientProbeConfig **p) {
-        if (*p)
-                n_dhcp4_client_probe_config_free(*p);
-}
-
-static inline void n_dhcp4_client_probe_config_freev(NDhcp4ClientProbeConfig *p) {
-        n_dhcp4_client_probe_config_free(p);
-}
-
-static inline void n_dhcp4_client_unrefp(NDhcp4Client **p) {
-        if (*p)
-                n_dhcp4_client_unref(*p);
-}
-
-static inline void n_dhcp4_client_unrefv(NDhcp4Client *p) {
-        n_dhcp4_client_unref(p);
-}
-
-static inline void n_dhcp4_client_probe_freep(NDhcp4ClientProbe **p) {
-        if (*p)
-                n_dhcp4_client_probe_free(*p);
-}
-
-static inline void n_dhcp4_client_probe_freev(NDhcp4ClientProbe *p) {
-        n_dhcp4_client_probe_free(p);
-}
-
-static inline void n_dhcp4_client_lease_unrefp(NDhcp4ClientLease **p) {
-        if (*p)
-                n_dhcp4_client_lease_unref(*p);
-}
-
-static inline void n_dhcp4_client_lease_unrefv(NDhcp4ClientLease *p) {
-        n_dhcp4_client_lease_unref(p);
-}
-
-static inline void n_dhcp4_server_config_freep(NDhcp4ServerConfig **p) {
-        if (*p)
-                n_dhcp4_server_config_free(*p);
-}
-
-static inline void n_dhcp4_server_config_freev(NDhcp4ServerConfig *p) {
-        n_dhcp4_server_config_free(p);
-}
-
-static inline void n_dhcp4_server_unrefp(NDhcp4Server **p) {
-        if (*p)
-                n_dhcp4_server_unref(*p);
-}
-
-static inline void n_dhcp4_server_unrefv(NDhcp4Server *p) {
-        n_dhcp4_server_unref(p);
-}
-
-static inline void n_dhcp4_server_ip_freep(NDhcp4ServerIp **p) {
-        if (*p)
-                n_dhcp4_server_ip_free(*p);
-}
-
-static inline void n_dhcp4_server_ip_freev(NDhcp4ServerIp *p) {
-        n_dhcp4_server_ip_free(p);
-}
-
-static inline void n_dhcp4_server_lease_unrefp(NDhcp4ServerLease **p) {
-        if (*p)
-                n_dhcp4_server_lease_unref(*p);
-}
-
-static inline void n_dhcp4_server_lease_unrefv(NDhcp4ServerLease *p) {
-        n_dhcp4_server_lease_unref(p);
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/shared/n-dhcp4/src/util/packet.c b/shared/n-dhcp4/src/util/packet.c
deleted file mode 100644
index 48f2c85e..00000000
--- a/shared/n-dhcp4/src/util/packet.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Packet Sockets
- */
-
-#include <assert.h>
-#include <c-stdaux.h>
-#include <endian.h>
-#include <errno.h>
-#include <linux/filter.h>
-#include <linux/if_ether.h>
-#include <linux/if_packet.h>
-#include <linux/udp.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "packet.h"
-
-/**
- * packet_internet_checksum() - compute the internet checksum
- * @data:               the data to checksum
- * @size:               the length of @data in bytes
- *
- * Computes the internet checksum for a given blob according to RFC1071.
- *
- * The internet checksum is the one's complement of the one's complement sum of
- * the 16-bit words of the data, padded with zero-bytes if the data does not
- * end on a 16-bit boundary.
- *
- * Return: Checksum is returned.
- */
-uint16_t packet_internet_checksum(const uint8_t *data, size_t size) {
-        uint64_t acc = 0;
-        uint32_t local;
-
-        while (size >= sizeof(local)) {
-                memcpy(&local, data, sizeof(local));
-                acc += local;
-
-                data += sizeof(local);
-                size -= sizeof(local);
-        }
-
-        if (size) {
-                local = 0;
-                memcpy(&local, data, size);
-                acc += local;
-        }
-
-        while (acc >> 16)
-                acc = (acc & 0xffff) + (acc >> 16);
-
-        return ~acc;
-}
-
-/**
- * packet_internet_checksum_udp() - compute the internet checkum for UDP packets
- * @src_addr:           source IP address
- * @dst_addr:           destination IP address
- * @src_port:           source port
- * @dst_port:           destination port
- * @data:               payload
- * @size:               length of payload in bytes
- * @checksum:           current checksum, or 0
- *
- * Computes the internet checksum for a UDP packet, given the relevant IP and
- * UDP header fields.
- *
- * Note that since a UDP packet contains the checksum itself, the resulting
- * checksum will always be 0 (this fact is used to verify that a UDP packet is
- * valid).
- * Inversely, when calculating the checksum for outgoing packets, you have to
- * specify 0 as @checksum, and this function will return the checksum for the
- * caller to use for the packet. In this case, though, the caller must check
- * whether the returned checksum might coincidentally be 0, in which case it
- * must be flipped to -1 (0xffff), since 0 is not allowed as checksum in UDP
- * packets, and -1 is arithmetically equivalent in the checksum calculation.
- *
- * Return: Checksum is returned.
- */
-uint16_t packet_internet_checksum_udp(const struct in_addr *src_addr,
-                                      const struct in_addr *dst_addr,
-                                      uint16_t src_port,
-                                      uint16_t dst_port,
-                                      const uint8_t *data,
-                                      size_t size,
-                                      uint16_t checksum) {
-        struct {
-                uint32_t src;
-                uint32_t dst;
-                uint8_t _zeros;
-                uint8_t protocol;
-                uint16_t length;
-                struct udphdr udp;
-        } _c_packed_ udp_phdr = {
-                .src = src_addr->s_addr,
-                .dst = dst_addr->s_addr,
-                .protocol = IPPROTO_UDP,
-                .length = htons(sizeof(struct udphdr) + size),
-                .udp = {
-                        .source = htons(src_port),
-                        .dest = htons(dst_port),
-                        .len = htons(sizeof(struct udphdr) + size),
-                        .check = checksum,
-                },
-        };
-        const uint8_t *iter;
-        uint64_t acc = 0;
-        uint32_t local;
-
-        _Static_assert(!(sizeof(udp_phdr) % sizeof(local)),
-                       "UDP header structure size is not a multiple of 4");
-
-        for (iter = (const uint8_t *)&udp_phdr;
-             iter < (const uint8_t *)(&udp_phdr + 1);
-             iter += sizeof(local)) {
-                memcpy(&local, iter, sizeof(local));
-                acc += local;
-        }
-
-        while (size >= sizeof(local)) {
-                memcpy(&local, data, sizeof(local));
-                acc += local;
-
-                data += sizeof(local);
-                size -= sizeof(local);
-        }
-
-        if (size) {
-                local = 0;
-                memcpy(&local, data, size);
-                acc += local;
-        }
-
-        while (acc >> 16)
-                acc = (acc & 0xffff) + (acc >> 16);
-
-        return ~acc;
-}
-
-/**
- * packet_sendto_udp() - send UDP packet on AF_PACKET socket
- * @sockfd:             AF_PACKET/SOCK_DGRAM socket
- * @buf:                payload
- * @n_buf:              length of payload in bytes
- * @n_transmittedp:     output argument for number of transmitted bytes
- * @src_paddr:          source protocol address, see ip(7)
- * @dest_haddr:         destination hardware address, see packet(7)
- * @dest_paddr:         destination protocol address, see ip(7)
- *
- * Sends an UDP packet on a AF_PACKET socket directly to a hardware
- * address. The difference between this and sendto() on an AF_INET
- * socket is that no routing is performed, so the packet is delivered
- * even if the destination IP is not yet configured on the destination
- * host.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int packet_sendto_udp(int sockfd,
-                      const void *buf,
-                      size_t n_buf,
-                      size_t *n_transmittedp,
-                      const struct sockaddr_in *src_paddr,
-                      const struct packet_sockaddr_ll *dest_haddr,
-                      const struct sockaddr_in *dest_paddr) {
-        struct iphdr ip_hdr = {
-                .version = IPVERSION,
-                .ihl = sizeof(ip_hdr) / 4, /* Length of header in multiples of four bytes */
-                .tos = IPTOS_CLASS_CS6, /* Class Selector for network control */
-                .tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + n_buf),
-                .frag_off = htons(IP_DF), /* Do not fragment */
-                .ttl = IPDEFTTL,
-                .protocol = IPPROTO_UDP,
-                .saddr = src_paddr->sin_addr.s_addr,
-                .daddr = dest_paddr->sin_addr.s_addr,
-        };
-        struct udphdr udp_hdr = {
-                .source = src_paddr->sin_port,
-                .dest = dest_paddr->sin_port,
-                .len = htons(sizeof(udp_hdr) + n_buf),
-        };
-        struct iovec iov[3] = {
-                {
-                        .iov_base = &ip_hdr,
-                        .iov_len = sizeof(ip_hdr),
-                },
-                {
-                        .iov_base = &udp_hdr,
-                        .iov_len = sizeof(udp_hdr),
-                },
-                {
-                        .iov_base = (void *)buf,
-                        .iov_len = n_buf,
-                },
-        };
-        struct msghdr msg = {
-                .msg_name = (void*)dest_haddr,
-                .msg_namelen = sizeof(*dest_haddr),
-                .msg_iov = iov,
-                .msg_iovlen = sizeof(iov) / sizeof(iov[0]),
-        };
-        ssize_t pktlen;
-
-        ip_hdr.check = packet_internet_checksum((void*)&ip_hdr, sizeof(ip_hdr));
-        udp_hdr.check = packet_internet_checksum_udp(&src_paddr->sin_addr,
-                                                     &dest_paddr->sin_addr,
-                                                     ntohs(src_paddr->sin_port),
-                                                     ntohs(dest_paddr->sin_port),
-                                                     buf,
-                                                     n_buf,
-                                                     0);
-
-        /*
-         * 0x0000 and 0xffff are equivalent for computing the UDP checksum,
-         * but 0x0000 is reserved in UDP headers, to mean that the checksum is
-         * not set and should be ignored by the receiver. Hence, flip it to
-         * 0xffff in that case.
-         */
-        udp_hdr.check = udp_hdr.check ?: 0xffff;
-
-        pktlen = sendmsg(sockfd, &msg, 0);
-        if (pktlen < 0)
-                return -c_errno();
-
-        /*
-         * Kernel never truncates. Worst case, we get -EMSGSIZE. Kernel *might*
-         * prepend VNET headers, in which case a bigger length than sent is
-         * returned.
-         * Lets assert on this, and then return to the caller the proportion of
-         * its own buffer that we sent (which is always exactly the requested
-         * size).
-         */
-        c_assert((size_t)pktlen >= sizeof(ip_hdr) + sizeof(udp_hdr) + n_buf);
-        *n_transmittedp = n_buf;
-        return 0;
-}
-
-/**
- * packet_recvfrom_upd() - receive UDP packet from AF_PACKET socket
- * @sockfd:             AF_PACKET/SOCK_DGRAM socket
- * @buf:                buffor for payload
- * @n_buf:              max length of payload in bytes
- * @n_transmittedp:     output argument for number transmitted bytes
- * @src:                return argument for source address, or NULL, see ip(7)
- *
- * Receives an UDP packet on a AF_PACKET socket. The difference between
- * this and recvfrom() on an AF_INET socket is that the packet will be
- * received even if the destination IP address has not been configured
- * on the interface.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int packet_recvfrom_udp(int sockfd,
-                        void *buf,
-                        size_t n_buf,
-                        size_t *n_transmittedp,
-                        struct sockaddr_in *src) {
-        union {
-                struct iphdr hdr;
-                /*
-                 * Maximum IP-header length is 15 * 4, since it is specified in
-                 * the `ihl` field, which is four bits and interpreted as
-                 * factor of 4. So maximum `ihl` value is `(2^4 - 1) * 4`.
-                 */
-                uint8_t data[15 * 4];
-        } ip_hdr;
-        struct udphdr udp_hdr;
-        struct iovec iov[3] = {
-                {
-                        .iov_base = &ip_hdr,
-                },
-                {
-                        .iov_base = &udp_hdr,
-                        .iov_len = sizeof(udp_hdr),
-                },
-                {
-                        .iov_base = buf,
-                        .iov_len = n_buf,
-                },
-        };
-        uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
-        struct msghdr msg = {
-                .msg_iov = iov,
-                .msg_iovlen = sizeof(iov) / sizeof(iov[0]),
-                .msg_control = cmsgbuf,
-                .msg_controllen = sizeof(cmsgbuf),
-        };
-        struct cmsghdr *cmsg;
-        bool checksum = true;
-        ssize_t pktlen;
-        size_t hdrlen;
-
-        *n_transmittedp = 0;
-
-        /* Peek packet to obtain the real IP header length */
-        pktlen = recv(sockfd, &ip_hdr.hdr, sizeof(ip_hdr.hdr), MSG_PEEK);
-        if (pktlen < 0)
-                return -errno;
-
-        if ((size_t)pktlen < sizeof(ip_hdr.hdr)) {
-                /*
-                 * Received packet is smaller than the minimal IP header length,
-                 * discard it.
-                 */
-                recv(sockfd, NULL, 0, 0);
-                return 0;
-        }
-
-        if (ip_hdr.hdr.version != IPVERSION) {
-                /*
-                 * This is not an IPv4 packet, discard it.
-                 */
-                recv(sockfd, NULL, 0, 0);
-                return 0;
-        }
-
-        hdrlen = ip_hdr.hdr.ihl * 4;
-        if (hdrlen < sizeof(ip_hdr.hdr)) {
-                /*
-                 * The length given in the header is smaller than the minimum
-                 * header length, discard the packet.
-                 */
-                recv(sockfd, NULL, 0, 0);
-                return 0;
-        }
-
-        /*
-         * Now that we know the ip-header length, we can prepare the iovec to
-         * read the entire packet into the correct buffers.
-         */
-        iov[0].iov_len = hdrlen;
-        pktlen = recvmsg(sockfd, &msg, 0);
-        if (pktlen < 0)
-                return -errno;
-
-        cmsg = CMSG_FIRSTHDR(&msg);
-        if (cmsg) {
-                if (cmsg->cmsg_level == SOL_PACKET &&
-                    cmsg->cmsg_type == PACKET_AUXDATA &&
-                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
-                        struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
-                        checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
-                }
-        }
-
-        if (ntohs(ip_hdr.hdr.tot_len) > pktlen) {
-                /*
-                 * The IP-packet is bigger than the chunk returned by the
-                 * kernel. So either the packet is corrupt, or our caller
-                 * provided too small a buffer. In both cases, we simply drop
-                 * the packet.
-                 */
-                return 0;
-        }
-
-        /* Truncate trailing garbage. */
-        pktlen = ntohs(ip_hdr.hdr.tot_len);
-
-        if ((size_t)pktlen < hdrlen + sizeof(udp_hdr)) {
-                /*
-                 * The packet is too small to even contain an entire UDP
-                 * header, so discard it entirely.
-                 */
-                return 0;
-        } else if ((size_t)pktlen < hdrlen + ntohs(udp_hdr.len)) {
-                /*
-                 * The UDP header specified a longer length than the returned
-                 * packet, so discard it entirely.
-                 */
-                return 0;
-        }
-
-        /*
-         * Make @pktlen the length of the packet payload, without IP/UDP
-         * headers, since that is what the caller is interested in.
-         */
-        pktlen = ntohs(udp_hdr.len) - sizeof(struct udphdr);
-
-        /* IP */
-
-        if (ip_hdr.hdr.protocol != IPPROTO_UDP) {
-                return 0; /* not a UDP packet, discard it */
-        } else if (ip_hdr.hdr.frag_off & htons(IP_MF | IP_OFFMASK)) {
-                return 0; /* fragmented packet, discard it */
-        } else if (checksum && packet_internet_checksum(ip_hdr.data, hdrlen)) {
-                return 0; /* invalid checksum, discard it */
-        }
-
-        /* UDP */
-
-        if (checksum && udp_hdr.check) {
-                /*
-                 * Computing the checksum of a packet that has the checksum set
-                 * must yield 0. If it does not yield 0, the packet is invalid,
-                 * in which case we discard it.
-                 */
-               if (packet_internet_checksum_udp(&(struct in_addr){ ip_hdr.hdr.saddr },
-                                                &(struct in_addr){ ip_hdr.hdr.daddr },
-                                                ntohs(udp_hdr.source),
-                                                ntohs(udp_hdr.dest),
-                                                buf,
-                                                pktlen,
-                                                udp_hdr.check)) {
-                        return 0;
-               }
-        }
-
-        if (src) {
-                src->sin_family = AF_INET;
-                src->sin_addr.s_addr = ip_hdr.hdr.saddr;
-                src->sin_port = udp_hdr.source;
-        }
-
-        /* Return length of UDP payload (i.e., data written to @buf). */
-        *n_transmittedp = pktlen;
-        return 0;
-}
-
-/**
- * packet_shutdown() - shutdown socket for future receive operations
- * @sockfd:     socket
- *
- * Partially emulates `shutdown(sockfd, SHUT_RD)`, in the sense that no
- * further packets may be queued on the socket. All packets that are
- * already queued will still be delivered, but once -EAGAIN is returned
- * we are guaranteed never to be able to read more packets in the future.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int packet_shutdown(int sockfd) {
-        struct sock_filter filter[] = {
-                BPF_STMT(BPF_RET + BPF_K, 0), /* discard all packets */
-        };
-        struct sock_fprog fprog = {
-                .filter = filter,
-                .len = sizeof(filter) / sizeof(filter[0]),
-        };
-        int r;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/util/packet.h b/shared/n-dhcp4/src/util/packet.h
deleted file mode 100644
index 98dabf7f..00000000
--- a/shared/n-dhcp4/src/util/packet.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#pragma once
-
-/*
- * Packet Sockets
- */
-
-#include <c-stdaux.h>
-#include <inttypes.h>
-#include <linux/if_packet.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-/*
- * `struct sockaddr_ll` is too small to fit the Infiniband hardware address.
- * Introduce `struct packet_sockaddr_ll` which is the same as the original,
- * except the `sl_addr` field is extended to fit all the supported hardware
- * addresses.
- */
-struct packet_sockaddr_ll {
-        unsigned short  sll_family;
-        __be16          sll_protocol;
-        int             sll_ifindex;
-        unsigned short  sll_hatype;
-        unsigned char   sll_pkttype;
-        unsigned char   sll_halen;
-        unsigned char   sll_addr[32]; /* MAX_ADDR_LEN */
-};
-
-uint16_t packet_internet_checksum(const uint8_t *data, size_t len);
-uint16_t packet_internet_checksum_udp(const struct in_addr *src_addr,
-                                      const struct in_addr *dst_addr,
-                                      uint16_t src_port,
-                                      uint16_t dst_port,
-                                      const uint8_t *data,
-                                      size_t size,
-                                      uint16_t checksum);
-
-int packet_sendto_udp(int sockfd,
-                      const void *buf,
-                      size_t n_buf,
-                      size_t *n_transmittedp,
-                      const struct sockaddr_in *src_paddr,
-                      const struct packet_sockaddr_ll *dest_haddr,
-                      const struct sockaddr_in *dest_paddr);
-int packet_recvfrom_udp(int sockfd,
-                        void *buf,
-                        size_t n_buf,
-                        size_t *n_transmittedp,
-                        struct sockaddr_in *src);
-
-int packet_shutdown(int sockfd);
-
-/* inline helpers */
-
-static inline int packet_recv_udp(int sockfd,
-                                  void *buf,
-                                  size_t n_buf,
-                                  size_t *n_transmittedp) {
-        return packet_recvfrom_udp(sockfd, buf, n_buf, n_transmittedp, NULL);
-}
diff --git a/shared/n-dhcp4/src/util/socket.c b/shared/n-dhcp4/src/util/socket.c
deleted file mode 100644
index c25f76fd..00000000
--- a/shared/n-dhcp4/src/util/socket.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Socket Utilities
- */
-
-#include <assert.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <net/if.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include "socket.h"
-
-/**
- * socket_SIOCGIFNAME() - resolve an ifindex to an ifname
- * @socket:                     socket to operate on
- * @ifindex:                    index of network interface to resolve
- * @ifname:                     buffer to store resolved name
- *
- * This uses the SIOCGIFNAME ioctl to resolve an ifindex to an ifname. The
- * buffer provided in @ifnamep must be at least IFNAMSIZ bytes in size. The
- * maximum ifname length is IFNAMSIZ-1, and this function always
- * zero-terminates the result.
- *
- * This function is similar to if_indextoname(3) provided by glibc, but it
- * allows to specify the target socket explicitly. This allows the caller to
- * control the target network-namespace, rather than relying on the network
- * namespace of the running process.
- *
- * Return: 0 on success, negative kernel error code on failure.
- */
-int socket_SIOCGIFNAME(int socket, int ifindex, char (*ifnamep)[IFNAMSIZ]) {
-        struct ifreq req = { .ifr_ifindex = ifindex };
-        int r;
-
-        r = ioctl(socket, SIOCGIFNAME, &req);
-        if (r < 0)
-                return -errno;
-
-        /*
-         * The linux kernel guarantees that an interface name is always
-         * zero-terminated, and it always fully fits into IFNAMSIZ bytes,
-         * including the zero-terminator.
-         */
-        memcpy(ifnamep, req.ifr_name, IFNAMSIZ);
-        return 0;
-}
-
-/**
- * socket_bind_if() - bind socket to a network interface
- * @socket:                     socket to operate on
- * @ifindex:                    index of network interface to bind to, or 0
- *
- * This binds the socket given via @socket to the network interface specified
- * via @ifindex. It uses the underlying SO_BINDTODEVICE ioctl of the linux
- * kernel. However, if available, if prefers the newer SO_BINDTOIFINDEX ioctl,
- * which avoids resolving the interface name temporarily, and thus does not
- * suffer from a race-condition.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int socket_bind_if(int socket, int ifindex) {
-        char ifname[IFNAMSIZ] = {};
-        int r;
-
-        c_assert(ifindex >= 0);
-
-        /*
-         * We first try the newer SO_BINDTOIFINDEX. If it is not available on
-         * the running kernel, we fall back to SO_BINDTODEVICE. This, however,
-         * requires us to first resolve the ifindex to an ifname. Note that
-         * this is racy, since the device name might theoretically change
-         * asynchronously.
-         *
-         * Using 0 as ifindex will remove the device-binding. For
-         * SO_BINDTOIFINDEX we simply pass-through the 0 to the kernel, which
-         * recognizes this correctly. For SO_BINDTODEVICE we pass the empty
-         * string, which the kernel recognizes as a request to remove the
-         * binding.
-         *
-         * The commit introducing SO_BINDTOIFINDEX first appeared in linux-5.1:
-         *
-         *     commit f5dd3d0c9638a9d9a02b5964c4ad636f06cf7e2c
-         *     Author: David Herrmann <dh.herrmann@gmail.com>
-         *     Date:   Tue Jan 15 14:42:14 2019 +0100
-         *
-         *         net: introduce SO_BINDTOIFINDEX sockopt
-         *
-         * In older kernels, setsockopt(2) is guaranteed to return ENOPROTOOPT
-         * for this ioctl.
-         */
-
-#ifdef SO_BINDTOIFINDEX
-        r = setsockopt(socket,
-                       SOL_SOCKET,
-                       SO_BINDTOIFINDEX,
-                       &ifindex,
-                       sizeof(ifindex));
-        if (r >= 0)
-                return 0;
-        else if (errno != ENOPROTOOPT)
-                return -errno;
-#endif /* SO_BINDTOIFINDEX */
-
-        if (ifindex > 0) {
-                r = socket_SIOCGIFNAME(socket, ifindex, &ifname);
-                if (r)
-                        return r;
-        }
-
-        r = setsockopt(socket,
-                       SOL_SOCKET,
-                       SO_BINDTODEVICE,
-                       ifname,
-                       strlen(ifname));
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/util/socket.h b/shared/n-dhcp4/src/util/socket.h
deleted file mode 100644
index b5ecf2c2..00000000
--- a/shared/n-dhcp4/src/util/socket.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-
-/*
- * Socket Utilities
- */
-
-#include <c-stdaux.h>
-#include <stdlib.h>
-
-int socket_SIOCGIFNAME(int socket, int ifindex, char (*ifnamep)[IFNAMSIZ]);
-int socket_bind_if(int socket, int ifindex);