chiark / gitweb /
bus-kernel: move bus_kernel_make_message
[elogind.git] / src / libsystemd / sd-dhcp-client.c
index 76abcbd2ac9d08d9a4da3cd7597973b91f15415c..a057852e360885a52ae3295afc1234e063225aa7 100644 (file)
@@ -41,8 +41,11 @@ struct DHCPLease {
         be32_t server_address;
         be32_t subnet_mask;
         be32_t router;
-        struct in_addr **dns;
+        struct in_addr *dns;
+        size_t dns_size;
         uint16_t mtu;
+        char *domainname;
+        char *hostname;
 };
 
 typedef struct DHCPLease DHCPLease;
@@ -50,6 +53,7 @@ typedef struct DHCPLease DHCPLease;
 struct sd_dhcp_client {
         DHCPState state;
         sd_event *event;
+        int event_priority;
         sd_event_source *timeout_resend;
         int index;
         int fd;
@@ -85,8 +89,7 @@ static int client_receive_message(sd_event_source *s, int fd,
                                   uint32_t revents, void *userdata);
 
 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
-                                void *userdata)
-{
+                                void *userdata) {
         assert_return(client, -EINVAL);
 
         client->cb = cb;
@@ -95,8 +98,7 @@ int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
         return 0;
 }
 
-int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option)
-{
+int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
         size_t i;
 
         assert_return(client, -EINVAL);
@@ -128,8 +130,7 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option)
 }
 
 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
-                                       const struct in_addr *last_addr)
-{
+                                       const struct in_addr *last_addr) {
         assert_return(client, -EINVAL);
         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
 
@@ -141,8 +142,7 @@ int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
         return 0;
 }
 
-int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index)
-{
+int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
         assert_return(client, -EINVAL);
         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
         assert_return(interface_index >= -1, -EINVAL);
@@ -153,8 +153,7 @@ int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index)
 }
 
 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
-                           const struct ether_addr *addr)
-{
+                           const struct ether_addr *addr) {
         assert_return(client, -EINVAL);
         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
 
@@ -163,8 +162,7 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client,
         return 0;
 }
 
-int sd_dhcp_client_get_address(sd_dhcp_client *client, struct in_addr *addr)
-{
+int sd_dhcp_client_get_address(sd_dhcp_client *client, struct in_addr *addr) {
         assert_return(client, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -187,8 +185,7 @@ int sd_dhcp_client_get_address(sd_dhcp_client *client, struct in_addr *addr)
         return 0;
 }
 
-int sd_dhcp_client_get_mtu(sd_dhcp_client *client, uint16_t *mtu)
-{
+int sd_dhcp_client_get_mtu(sd_dhcp_client *client, uint16_t *mtu) {
         assert_return(client, -EINVAL);
         assert_return(mtu, -EINVAL);
 
@@ -214,10 +211,10 @@ int sd_dhcp_client_get_mtu(sd_dhcp_client *client, uint16_t *mtu)
         return 0;
 }
 
-int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr ***addr)
-{
+int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr **addr, size_t *addr_size) {
         assert_return(client, -EINVAL);
         assert_return(addr, -EINVAL);
+        assert_return(addr_size, -EINVAL);
 
         switch (client->state) {
         case DHCP_STATE_INIT:
@@ -230,8 +227,35 @@ int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr ***addr)
         case DHCP_STATE_BOUND:
         case DHCP_STATE_RENEWING:
         case DHCP_STATE_REBINDING:
-                if (client->lease->dns)
+                if (client->lease->dns_size) {
+                        *addr_size = client->lease->dns_size;
                         *addr = client->lease->dns;
+                } else
+                        return -ENOENT;
+
+                break;
+        }
+
+        return 0;
+}
+
+int sd_dhcp_client_get_domainname(sd_dhcp_client *client, const char **domainname) {
+        assert_return(client, -EINVAL);
+        assert_return(domainname, -EINVAL);
+
+        switch (client->state) {
+        case DHCP_STATE_INIT:
+        case DHCP_STATE_SELECTING:
+        case DHCP_STATE_INIT_REBOOT:
+        case DHCP_STATE_REBOOTING:
+        case DHCP_STATE_REQUESTING:
+                return -EADDRNOTAVAIL;
+
+        case DHCP_STATE_BOUND:
+        case DHCP_STATE_RENEWING:
+        case DHCP_STATE_REBINDING:
+                if (client->lease->domainname)
+                        *domainname = client->lease->domainname;
                 else
                         return -ENOENT;
 
@@ -241,8 +265,33 @@ int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr ***addr)
         return 0;
 }
 
-int sd_dhcp_client_prefixlen(const struct in_addr *addr)
-{
+int sd_dhcp_client_get_hostname(sd_dhcp_client *client, const char **hostname) {
+        assert_return(client, -EINVAL);
+        assert_return(hostname, -EINVAL);
+
+        switch (client->state) {
+        case DHCP_STATE_INIT:
+        case DHCP_STATE_SELECTING:
+        case DHCP_STATE_INIT_REBOOT:
+        case DHCP_STATE_REBOOTING:
+        case DHCP_STATE_REQUESTING:
+                return -EADDRNOTAVAIL;
+
+        case DHCP_STATE_BOUND:
+        case DHCP_STATE_RENEWING:
+        case DHCP_STATE_REBINDING:
+                if (client->lease->hostname)
+                        *hostname = client->lease->hostname;
+                else
+                        return -ENOENT;
+
+                break;
+        }
+
+        return 0;
+}
+
+int sd_dhcp_client_prefixlen(const struct in_addr *addr) {
         int len = 0;
         uint32_t mask;
 
@@ -257,8 +306,7 @@ int sd_dhcp_client_prefixlen(const struct in_addr *addr)
         return len;
 }
 
-int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr)
-{
+int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr) {
         assert_return(client, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -281,8 +329,7 @@ int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr)
         return 0;
 }
 
-int sd_dhcp_client_get_netmask(sd_dhcp_client *client, struct in_addr *addr)
-{
+int sd_dhcp_client_get_netmask(sd_dhcp_client *client, struct in_addr *addr) {
         assert_return(client, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -305,28 +352,27 @@ int sd_dhcp_client_get_netmask(sd_dhcp_client *client, struct in_addr *addr)
         return 0;
 }
 
-static int client_notify(sd_dhcp_client *client, int event)
-{
+static int client_notify(sd_dhcp_client *client, int event) {
         if (client->cb)
                 client->cb(client, event, client->userdata);
 
         return 0;
 }
 
-static void in_addrs_free(struct in_addr **addrs) {
-        unsigned i;
-
-        if (!addrs)
+static void lease_free(DHCPLease *lease) {
+        if (!lease)
                 return;
 
-        for (i = 0; addrs[i]; i++)
-                free(addrs[i]);
-
-        free(addrs);
+        free(lease->hostname);
+        free(lease->domainname);
+        free(lease->dns);
+        free(lease);
 }
 
-static int client_stop(sd_dhcp_client *client, int error)
-{
+DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease*, lease_free);
+#define _cleanup_lease_free_ _cleanup_(lease_freep)
+
+static int client_stop(sd_dhcp_client *client, int error) {
         assert_return(client, -EINVAL);
 
         client->receive_message =
@@ -366,8 +412,7 @@ static int client_stop(sd_dhcp_client *client, int error)
         }
 
         if (client->lease) {
-                in_addrs_free(client->lease->dns);
-                free(client->lease);
+                lease_free(client->lease);
                 client->lease = NULL;
         }
 
@@ -376,8 +421,7 @@ static int client_stop(sd_dhcp_client *client, int error)
 
 static int client_packet_init(sd_dhcp_client *client, uint8_t type,
                               DHCPMessage *message, uint16_t secs,
-                              uint8_t **opt, size_t *optlen)
-{
+                              uint8_t **opt, size_t *optlen) {
         int err;
         be16_t max_size;
 
@@ -443,8 +487,7 @@ static int client_packet_init(sd_dhcp_client *client, uint8_t type,
         return 0;
 }
 
-static uint16_t client_checksum(void *buf, int len)
-{
+static uint16_t client_checksum(void *buf, int len) {
         uint32_t sum;
         uint16_t *check;
         int i;
@@ -467,8 +510,7 @@ static uint16_t client_checksum(void *buf, int len)
         return ~sum;
 }
 
-static void client_append_ip_headers(DHCPPacket *packet, uint16_t len)
-{
+static void client_append_ip_headers(DHCPPacket *packet, uint16_t len) {
         packet->ip.version = IPVERSION;
         packet->ip.ihl = DHCP_IP_SIZE / 4;
         packet->ip.tot_len = htobe16(len);
@@ -489,8 +531,7 @@ static void client_append_ip_headers(DHCPPacket *packet, uint16_t len)
         packet->ip.check = client_checksum(&packet->ip, DHCP_IP_SIZE);
 }
 
-static int client_send_discover(sd_dhcp_client *client, uint16_t secs)
-{
+static int client_send_discover(sd_dhcp_client *client, uint16_t secs) {
         int err = 0;
         _cleanup_free_ DHCPPacket *discover;
         size_t optlen, len;
@@ -529,8 +570,7 @@ static int client_send_discover(sd_dhcp_client *client, uint16_t secs)
         return err;
 }
 
-static int client_send_request(sd_dhcp_client *client, uint16_t secs)
-{
+static int client_send_request(sd_dhcp_client *client, uint16_t secs) {
         _cleanup_free_ DHCPPacket *request;
         size_t optlen, len;
         int err;
@@ -582,13 +622,16 @@ static int client_send_request(sd_dhcp_client *client, uint16_t secs)
 }
 
 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
-                                 void *userdata)
-{
+                                 void *userdata) {
         sd_dhcp_client *client = userdata;
         usec_t next_timeout = 0;
         uint32_t time_left;
         uint16_t secs;
-        int err = 0;
+        int r = 0;
+
+        assert(s);
+        assert(client);
+        assert(client->event);
 
         switch (client->state) {
         case DHCP_STATE_RENEWING:
@@ -627,19 +670,23 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
 
         next_timeout += (random_u32() & 0x1fffff);
 
-        err = sd_event_add_monotonic(client->event, next_timeout,
+        r = sd_event_add_monotonic(client->event, next_timeout,
                                      10 * USEC_PER_MSEC,
                                      client_timeout_resend, client,
                                      &client->timeout_resend);
-        if (err < 0)
+        if (r < 0)
+                goto error;
+
+        r = sd_event_source_set_priority(client->timeout_resend, client->event_priority);
+        if (r < 0)
                 goto error;
 
         secs = (usec - client->start_time) / USEC_PER_SEC;
 
         switch (client->state) {
         case DHCP_STATE_INIT:
-                err = client_send_discover(client, secs);
-                if (err >= 0) {
+                r = client_send_discover(client, secs);
+                if (r >= 0) {
                         client->state = DHCP_STATE_SELECTING;
                         client->attempt = 1;
                 } else {
@@ -650,8 +697,8 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
                 break;
 
         case DHCP_STATE_SELECTING:
-                err = client_send_discover(client, secs);
-                if (err < 0 && client->attempt >= 64)
+                r = client_send_discover(client, secs);
+                if (r < 0 && client->attempt >= 64)
                         goto error;
 
                 break;
@@ -659,8 +706,8 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
         case DHCP_STATE_REQUESTING:
         case DHCP_STATE_RENEWING:
         case DHCP_STATE_REBINDING:
-                err = client_send_request(client, secs);
-                if (err < 0 && client->attempt >= 64)
+                r = client_send_request(client, secs);
+                if (r < 0 && client->attempt >= 64)
                          goto error;
 
                 client->request_sent = usec;
@@ -677,26 +724,36 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
         return 0;
 
 error:
-        client_stop(client, err);
+        client_stop(client, r);
 
         /* Errors were dealt with when stopping the client, don't spill
            errors into the event loop handler */
         return 0;
 }
 
-static int client_initialize_events(sd_dhcp_client *client, usec_t usec)
-{
+static int client_initialize_events(sd_dhcp_client *client, usec_t usec) {
         int r;
 
+        assert(client);
+        assert(client->event);
+
         r = sd_event_add_io(client->event, client->fd, EPOLLIN,
                             client_receive_message, client,
                             &client->receive_message);
         if (r < 0)
                 goto error;
 
+        r = sd_event_source_set_priority(client->receive_message, client->event_priority);
+        if (r < 0)
+                goto error;
+
         r = sd_event_add_monotonic(client->event, usec, 0,
                                    client_timeout_resend, client,
                                    &client->timeout_resend);
+        if (r < 0)
+                goto error;
+
+        r = sd_event_source_set_priority(client->timeout_resend, client->event_priority);
 
 error:
         if (r < 0)
@@ -707,8 +764,7 @@ error:
 }
 
 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
-                                 void *userdata)
-{
+                                 void *userdata) {
         sd_dhcp_client *client = userdata;
 
         client_stop(client, DHCP_EVENT_EXPIRED);
@@ -716,8 +772,7 @@ static int client_timeout_expire(sd_event_source *s, uint64_t usec,
         return 0;
 }
 
-static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
-{
+static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
         sd_dhcp_client *client = userdata;
         int r;
 
@@ -742,8 +797,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
         return client_initialize_events(client, usec);
 }
 
-static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
-{
+static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
         sd_dhcp_client *client = userdata;
         int r;
 
@@ -763,8 +817,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
 }
 
 static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
-                              void *user_data)
-{
+                              void *user_data) {
         DHCPLease *lease = user_data;
         be32_t val;
 
@@ -800,18 +853,16 @@ static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
                 if (len >= 4) {
                         unsigned i;
 
-                        in_addrs_free(lease->dns);
+                        lease->dns_size = len / 4;
 
-                        lease->dns = new0(struct in_addr*, len / 4 + 1);
+                        free(lease->dns);
+                        lease->dns = new0(struct in_addr, lease->dns_size);
                         if (!lease->dns)
                                 return -ENOMEM;
 
-                        for (i = 0; i < len / 4; i++) {
-                                lease->dns[i] = new0(struct in_addr, 1);
-                                memcpy(&lease->dns[i]->s_addr, option + 4 * i, 4);
+                        for (i = 0; i < lease->dns_size; i++) {
+                                memcpy(&lease->dns[i].s_addr, option + 4 * i, 4);
                         }
-
-                        lease->dns[len / 4] = NULL;
                 }
 
                 break;
@@ -829,6 +880,22 @@ static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
 
                 break;
 
+        case DHCP_OPTION_DOMAIN_NAME:
+                if (len >= 1) {
+                        free(lease->domainname);
+                        lease->domainname = strndup((const char *)option, len);
+                }
+
+                break;
+
+        case DHCP_OPTION_HOST_NAME:
+                if (len >= 1) {
+                        free(lease->hostname);
+                        lease->hostname = strndup((const char *)option, len);
+                }
+
+                break;
+
         case DHCP_OPTION_RENEWAL_T1_TIME:
                 if (len == 4) {
                         memcpy(&val, option, 4);
@@ -850,8 +917,7 @@ static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
 }
 
 static int client_verify_headers(sd_dhcp_client *client, DHCPPacket *message,
-                                 size_t len)
-{
+                                 size_t len) {
         size_t hdrlen;
 
         if (len < (DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE))
@@ -887,23 +953,23 @@ static int client_verify_headers(sd_dhcp_client *client, DHCPPacket *message,
 }
 
 static int client_receive_offer(sd_dhcp_client *client, DHCPPacket *offer,
-                                size_t len)
-{
-        int err;
-        DHCPLease *lease;
+                                size_t len) {
+        _cleanup_lease_free_ DHCPLease *lease = NULL;
+        int r;
 
-        err = client_verify_headers(client, offer, len);
-        if (err < 0)
-                return err;
+        r = client_verify_headers(client, offer, len);
+        if (r < 0)
+                return r;
 
         lease = new0(DHCPLease, 1);
         if (!lease)
                 return -ENOMEM;
 
         len = len - DHCP_IP_UDP_SIZE;
-        if (dhcp_option_parse(&offer->dhcp, len, client_parse_offer,
-                              lease) != DHCP_OFFER)
-                goto error;
+        r = dhcp_option_parse(&offer->dhcp, len, client_parse_offer,
+                              lease);
+        if (r != DHCP_OFFER)
+                return -ENOMSG;
 
         lease->address = offer->dhcp.yiaddr;
 
@@ -911,25 +977,20 @@ static int client_receive_offer(sd_dhcp_client *client, DHCPPacket *offer,
             lease->server_address == INADDR_ANY ||
             lease->subnet_mask == INADDR_ANY ||
             lease->lifetime == 0)
-                goto error;
+                return -ENOMSG;
 
         client->lease = lease;
+        lease = NULL;
 
         return 0;
-
-error:
-        free(lease);
-
-        return -ENOMSG;
 }
 
 static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf,
-                              size_t len)
-{
-        int r;
+                              size_t len) {
         DHCPPacket *ack;
         DHCPMessage *dhcp;
-        DHCPLease *lease;
+        _cleanup_lease_free_ DHCPLease *lease = NULL;
+        int r;
 
         if (client->state == DHCP_STATE_RENEWING) {
                 dhcp = (DHCPMessage *)buf;
@@ -949,25 +1010,18 @@ static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf,
                 return -ENOMEM;
 
         r = dhcp_option_parse(dhcp, len, client_parse_offer, lease);
+        if (r == DHCP_NAK)
+                return DHCP_EVENT_NO_LEASE;
 
-        if (r == DHCP_NAK) {
-                r = DHCP_EVENT_NO_LEASE;
-                goto error;
-        }
-
-        if (r != DHCP_ACK) {
-                r = -ENOMSG;
-                goto error;
-        }
+        if (r != DHCP_ACK)
+                return -ENOMSG;
 
         lease->address = dhcp->yiaddr;
 
         if (lease->address == INADDR_ANY ||
             lease->server_address == INADDR_ANY ||
-            lease->subnet_mask == INADDR_ANY || lease->lifetime == 0) {
-                r = -ENOMSG;
-                goto error;
-        }
+            lease->subnet_mask == INADDR_ANY || lease->lifetime == 0)
+                return -ENOMSG;
 
         r = DHCP_EVENT_IP_ACQUIRE;
         if (client->lease) {
@@ -977,30 +1031,27 @@ static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf,
                         r = DHCP_EVENT_IP_CHANGE;
                 }
 
-                free(client->lease);
+                lease_free(client->lease);
         }
 
         client->lease = lease;
-
-        return r;
-
-error:
-        free(lease);
+        lease = NULL;
 
         return r;
 }
 
 static uint64_t client_compute_timeout(uint64_t request_sent,
-                                       uint32_t lifetime)
-{
+                                       uint32_t lifetime) {
         return request_sent + (lifetime - 3) * USEC_PER_SEC +
                 + (random_u32() & 0x1fffff);
 }
 
-static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec)
-{
-        int err;
+static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec) {
         uint64_t next_timeout;
+        int r;
+
+        assert(client);
+        assert(client->event);
 
         if (client->lease->lifetime < 10)
                 return -EINVAL;
@@ -1017,12 +1068,16 @@ static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec)
         if (next_timeout < usec)
                 return -EINVAL;
 
-        err = sd_event_add_monotonic(client->event, next_timeout,
+        r = sd_event_add_monotonic(client->event, next_timeout,
                                      10 * USEC_PER_MSEC,
                                      client_timeout_t1, client,
                                      &client->timeout_t1);
-        if (err < 0)
-                return err;
+        if (r < 0)
+                return r;
+
+        r = sd_event_source_set_priority(client->timeout_t1, client->event_priority);
+        if (r < 0)
+                return r;
 
         if (!client->lease->t2)
                 client->lease->t2 = client->lease->lifetime * 7 / 8;
@@ -1038,31 +1093,38 @@ static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec)
         if (next_timeout < usec)
                 return -EINVAL;
 
-        err = sd_event_add_monotonic(client->event, next_timeout,
+        r = sd_event_add_monotonic(client->event, next_timeout,
                                      10 * USEC_PER_MSEC,
                                      client_timeout_t2, client,
                                      &client->timeout_t2);
-        if (err < 0)
-                return err;
+        if (r < 0)
+                return r;
+
+        r = sd_event_source_set_priority(client->timeout_t2, client->event_priority);
+        if (r < 0)
+                return r;
 
         next_timeout = client_compute_timeout(client->request_sent,
                                               client->lease->lifetime);
         if (next_timeout < usec)
                 return -EINVAL;
 
-        err = sd_event_add_monotonic(client->event, next_timeout,
+        r = sd_event_add_monotonic(client->event, next_timeout,
                                      10 * USEC_PER_MSEC,
                                      client_timeout_expire, client,
                                      &client->timeout_expire);
-        if (err < 0)
-                return err;
+        if (r < 0)
+                return r;
+
+        r = sd_event_source_set_priority(client->timeout_expire, client->event_priority);
+        if (r < 0)
+                return r;
 
         return 0;
 }
 
 static int client_receive_message(sd_event_source *s, int fd,
-                                  uint32_t revents, void *userdata)
-{
+                                  uint32_t revents, void *userdata) {
         sd_dhcp_client *client = userdata;
         uint8_t buf[sizeof(DHCPPacket) + DHCP_CLIENT_MIN_OPTIONS_SIZE];
         int buflen = sizeof(buf);
@@ -1070,6 +1132,10 @@ static int client_receive_message(sd_event_source *s, int fd,
         DHCPPacket *message;
         usec_t time_now;
 
+        assert(s);
+        assert(client);
+        assert(client->event);
+
         len = read(fd, &buf, buflen);
         if (len < 0)
                 return 0;
@@ -1097,6 +1163,10 @@ static int client_receive_message(sd_event_source *s, int fd,
                                                    &client->timeout_resend);
                         if (r < 0)
                                 goto error;
+
+                        r = sd_event_source_set_priority(client->timeout_resend, client->event_priority);
+                        if (r < 0)
+                                goto error;
                 }
 
                 break;
@@ -1156,11 +1226,11 @@ error:
         return 0;
 }
 
-int sd_dhcp_client_start(sd_dhcp_client *client)
-{
+int sd_dhcp_client_start(sd_dhcp_client *client) {
         int r;
 
         assert_return(client, -EINVAL);
+        assert_return(client->event, -EINVAL);
         assert_return(client->index > 0, -EINVAL);
         assert_return(client->state == DHCP_STATE_INIT ||
                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
@@ -1180,35 +1250,67 @@ int sd_dhcp_client_start(sd_dhcp_client *client)
         return client_initialize_events(client, client->start_time);
 }
 
-int sd_dhcp_client_stop(sd_dhcp_client *client)
-{
+int sd_dhcp_client_stop(sd_dhcp_client *client) {
         return client_stop(client, DHCP_EVENT_STOP);
 }
 
-sd_dhcp_client *sd_dhcp_client_free(sd_dhcp_client *client)
-{
-        assert_return(client, NULL);
+int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int priority) {
+        int r;
+
+        assert_return(client, -EINVAL);
+        assert_return(!client->event, -EBUSY);
+
+        if (event)
+                client->event = sd_event_ref(event);
+        else {
+                r = sd_event_default(&client->event);
+                if (r < 0)
+                        return 0;
+        }
+
+        client->event_priority = priority;
+
+        return 0;
+}
+
+int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
+        assert_return(client, -EINVAL);
+
+        client->event = sd_event_unref(client->event);
+
+        return 0;
+}
+
+sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
+        if (!client)
+                return NULL;
+
+        return client->event;
+}
+
+void sd_dhcp_client_free(sd_dhcp_client *client) {
+        if (!client)
+                return;
 
         sd_dhcp_client_stop(client);
+        sd_dhcp_client_detach_event(client);
 
-        sd_event_unref(client->event);
         free(client->req_opts);
         free(client);
-
-        return NULL;
 }
 
-sd_dhcp_client *sd_dhcp_client_new(sd_event *event)
-{
-        sd_dhcp_client *client;
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_free);
+#define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_freep)
+
+int sd_dhcp_client_new(sd_dhcp_client **ret) {
+        _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
 
-        assert_return(event, NULL);
+        assert_return(ret, -EINVAL);
 
         client = new0(sd_dhcp_client, 1);
         if (!client)
-                return NULL;
+                return -ENOMEM;
 
-        client->event = sd_event_ref(event);
         client->state = DHCP_STATE_INIT;
         client->index = -1;
         client->fd = -1;
@@ -1217,10 +1319,11 @@ sd_dhcp_client *sd_dhcp_client_new(sd_event *event)
         client->req_opts_size = ELEMENTSOF(default_req_opts);
 
         client->req_opts = memdup(default_req_opts, client->req_opts_size);
-        if (!client->req_opts) {
-                free(client);
-                return NULL;
-        }
+        if (!client->req_opts)
+                return -ENOMEM;
 
-        return client;
+        *ret = client;
+        client = NULL;
+
+        return 0;
 }