chiark / gitweb /
sd-dhcp-client: add support for FORCERENEW
[elogind.git] / src / libsystemd-network / sd-dhcp-client.c
1 /***
2   This file is part of systemd.
3
4   Copyright (C) 2013 Intel Corporation. All rights reserved.
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <net/ethernet.h>
25 #include <net/if_arp.h>
26 #include <netinet/ether.h>
27 #include <sys/param.h>
28 #include <sys/ioctl.h>
29
30 #include "util.h"
31 #include "list.h"
32 #include "refcnt.h"
33 #include "async.h"
34
35 #include "dhcp-protocol.h"
36 #include "dhcp-internal.h"
37 #include "dhcp-lease-internal.h"
38 #include "sd-dhcp-client.h"
39
40 struct sd_dhcp_client {
41         RefCount n_ref;
42
43         DHCPState state;
44         sd_event *event;
45         int event_priority;
46         sd_event_source *timeout_resend;
47         int index;
48         int fd;
49         union sockaddr_union link;
50         sd_event_source *receive_message;
51         bool request_broadcast;
52         uint8_t *req_opts;
53         size_t req_opts_allocated;
54         size_t req_opts_size;
55         be32_t last_addr;
56         struct {
57                 uint8_t type;
58                 struct ether_addr mac_addr;
59         } _packed_ client_id;
60         char *hostname;
61         char *vendor_class_identifier;
62         uint32_t xid;
63         usec_t start_time;
64         uint16_t secs;
65         unsigned int attempt;
66         usec_t request_sent;
67         sd_event_source *timeout_t1;
68         sd_event_source *timeout_t2;
69         sd_event_source *timeout_expire;
70         sd_dhcp_client_cb_t cb;
71         void *userdata;
72         sd_dhcp_lease *lease;
73 };
74
75 static const uint8_t default_req_opts[] = {
76         DHCP_OPTION_SUBNET_MASK,
77         DHCP_OPTION_ROUTER,
78         DHCP_OPTION_HOST_NAME,
79         DHCP_OPTION_DOMAIN_NAME,
80         DHCP_OPTION_DOMAIN_NAME_SERVER,
81         DHCP_OPTION_NTP_SERVER,
82 };
83
84 static int client_receive_message_raw(sd_event_source *s, int fd,
85                                       uint32_t revents, void *userdata);
86 static int client_receive_message_udp(sd_event_source *s, int fd,
87                                       uint32_t revents, void *userdata);
88 static void client_stop(sd_dhcp_client *client, int error);
89
90 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
91                                 void *userdata) {
92         assert_return(client, -EINVAL);
93
94         client->cb = cb;
95         client->userdata = userdata;
96
97         return 0;
98 }
99
100 int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
101         assert_return(client, -EINVAL);
102
103         client->request_broadcast = !!broadcast;
104
105         return 0;
106 }
107
108 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
109         size_t i;
110
111         assert_return(client, -EINVAL);
112         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
113                               DHCP_STATE_STOPPED), -EBUSY);
114
115         switch(option) {
116         case DHCP_OPTION_PAD:
117         case DHCP_OPTION_OVERLOAD:
118         case DHCP_OPTION_MESSAGE_TYPE:
119         case DHCP_OPTION_PARAMETER_REQUEST_LIST:
120         case DHCP_OPTION_END:
121                 return -EINVAL;
122
123         default:
124                 break;
125         }
126
127         for (i = 0; i < client->req_opts_size; i++)
128                 if (client->req_opts[i] == option)
129                         return -EEXIST;
130
131         if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
132                             client->req_opts_size + 1))
133                 return -ENOMEM;
134
135         client->req_opts[client->req_opts_size++] = option;
136
137         return 0;
138 }
139
140 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
141                                        const struct in_addr *last_addr) {
142         assert_return(client, -EINVAL);
143         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
144                               DHCP_STATE_STOPPED), -EBUSY);
145
146         if (last_addr)
147                 client->last_addr = last_addr->s_addr;
148         else
149                 client->last_addr = INADDR_ANY;
150
151         return 0;
152 }
153
154 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
155         assert_return(client, -EINVAL);
156         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
157                               DHCP_STATE_STOPPED), -EBUSY);
158         assert_return(interface_index > 0, -EINVAL);
159
160         client->index = interface_index;
161
162         return 0;
163 }
164
165 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
166                            const struct ether_addr *addr) {
167         DHCP_CLIENT_DONT_DESTROY(client);
168         bool need_restart = false;
169
170         assert_return(client, -EINVAL);
171         assert_return(addr, -EINVAL);
172
173         if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
174                 return 0;
175
176         if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
177                 log_dhcp_client(client, "Changing MAC address on running DHCP "
178                                 "client, restarting");
179                 need_restart = true;
180                 client_stop(client, DHCP_EVENT_STOP);
181         }
182
183         memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
184         client->client_id.type = 0x01;
185
186         if (need_restart && client->state != DHCP_STATE_STOPPED)
187                 sd_dhcp_client_start(client);
188
189         return 0;
190 }
191
192 int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
193                                 const char *hostname) {
194         char *new_hostname = NULL;
195
196         assert_return(client, -EINVAL);
197
198         if (streq_ptr(client->hostname, hostname))
199                 return 0;
200
201         if (hostname) {
202                 new_hostname = strdup(hostname);
203                 if (!new_hostname)
204                         return -ENOMEM;
205         }
206
207         free(client->hostname);
208         client->hostname = new_hostname;
209
210         return 0;
211 }
212
213 int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client,
214                                                const char *vci) {
215         char *new_vci = NULL;
216
217         assert_return(client, -EINVAL);
218
219         new_vci = strdup(vci);
220         if (!new_vci)
221                 return -ENOMEM;
222
223         free(client->vendor_class_identifier);
224
225         client->vendor_class_identifier = new_vci;
226
227         return 0;
228 }
229
230 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
231         assert_return(client, -EINVAL);
232         assert_return(ret, -EINVAL);
233
234         if (client->state != DHCP_STATE_BOUND &&
235             client->state != DHCP_STATE_RENEWING &&
236             client->state != DHCP_STATE_REBINDING)
237                 return -EADDRNOTAVAIL;
238
239         *ret = sd_dhcp_lease_ref(client->lease);
240
241         return 0;
242 }
243
244 static void client_notify(sd_dhcp_client *client, int event) {
245         if (client->cb)
246                 client->cb(client, event, client->userdata);
247 }
248
249 static int client_initialize(sd_dhcp_client *client) {
250         assert_return(client, -EINVAL);
251
252         client->receive_message =
253                 sd_event_source_unref(client->receive_message);
254
255         client->fd = asynchronous_close(client->fd);
256
257         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
258
259         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
260         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
261         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
262
263         client->attempt = 1;
264
265         client->state = DHCP_STATE_INIT;
266         client->xid = 0;
267
268         if (client->lease)
269                 client->lease = sd_dhcp_lease_unref(client->lease);
270
271         return 0;
272 }
273
274 static void client_stop(sd_dhcp_client *client, int error) {
275         assert(client);
276
277         if (error < 0)
278                 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
279         else if (error == DHCP_EVENT_STOP)
280                 log_dhcp_client(client, "STOPPED");
281         else
282                 log_dhcp_client(client, "STOPPED: Unknown event");
283
284         client_notify(client, error);
285
286         client_initialize(client);
287 }
288
289 static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
290                                uint8_t type, size_t *_optlen, size_t *_optoffset) {
291         _cleanup_free_ DHCPPacket *packet;
292         size_t optlen, optoffset, size;
293         be16_t max_size;
294         int r;
295
296         assert(client);
297         assert(client->secs);
298         assert(ret);
299         assert(_optlen);
300         assert(_optoffset);
301         assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
302
303         optlen = DHCP_MIN_OPTIONS_SIZE;
304         size = sizeof(DHCPPacket) + optlen;
305
306         packet = malloc0(size);
307         if (!packet)
308                 return -ENOMEM;
309
310         r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
311                               optlen, &optoffset);
312         if (r < 0)
313                 return r;
314
315         /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
316            refuse to issue an DHCP lease if 'secs' is set to zero */
317         packet->dhcp.secs = htobe16(client->secs);
318
319         /* RFC2132 section 4.1
320            A client that cannot receive unicast IP datagrams until its protocol
321            software has been configured with an IP address SHOULD set the
322            BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
323            DHCPREQUEST messages that client sends.  The BROADCAST bit will
324            provide a hint to the DHCP server and BOOTP relay agent to broadcast
325            any messages to the client on the client's subnet.
326
327            Note: some interfaces needs this to be enabled, but some networks
328            needs this to be disabled as broadcasts are filteretd, so this
329            needs to be configurable */
330         if (client->request_broadcast)
331                 packet->dhcp.flags = htobe16(0x8000);
332
333         /* RFC2132 section 4.1.1:
334            The client MUST include its hardware address in the ’chaddr’ field, if
335            necessary for delivery of DHCP reply messages.
336          */
337         memcpy(&packet->dhcp.chaddr, &client->client_id.mac_addr, ETH_ALEN);
338
339         /* Some DHCP servers will refuse to issue an DHCP lease if the Client
340            Identifier option is not set */
341         r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
342                                DHCP_OPTION_CLIENT_IDENTIFIER,
343                                sizeof(client->client_id), &client->client_id);
344         if (r < 0)
345                 return r;
346
347
348         /* RFC2131 section 3.5:
349            in its initial DHCPDISCOVER or DHCPREQUEST message, a
350            client may provide the server with a list of specific
351            parameters the client is interested in. If the client
352            includes a list of parameters in a DHCPDISCOVER message,
353            it MUST include that list in any subsequent DHCPREQUEST
354            messages.
355          */
356         r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
357                                DHCP_OPTION_PARAMETER_REQUEST_LIST,
358                                client->req_opts_size, client->req_opts);
359         if (r < 0)
360                 return r;
361
362         /* RFC2131 section 3.5:
363            The client SHOULD include the ’maximum DHCP message size’ option to
364            let the server know how large the server may make its DHCP messages.
365
366            Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
367            than the defined default size unless the Maximum Messge Size option
368            is explicitely set
369          */
370         max_size = htobe16(size);
371         r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
372                                DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
373                                2, &max_size);
374         if (r < 0)
375                 return r;
376
377         *_optlen = optlen;
378         *_optoffset = optoffset;
379         *ret = packet;
380         packet = NULL;
381
382         return 0;
383 }
384
385 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
386                                 size_t len) {
387         dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
388                                       INADDR_BROADCAST, DHCP_PORT_SERVER, len);
389
390         return dhcp_network_send_raw_socket(client->fd, &client->link,
391                                             packet, len);
392 }
393
394 static int client_send_discover(sd_dhcp_client *client) {
395         _cleanup_free_ DHCPPacket *discover = NULL;
396         size_t optoffset, optlen;
397         usec_t time_now;
398         int r;
399
400         assert(client);
401         assert(client->state == DHCP_STATE_INIT ||
402                client->state == DHCP_STATE_SELECTING);
403
404         /* See RFC2131 section 4.4.1 */
405
406         r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
407         if (r < 0)
408                 return r;
409         assert(time_now >= client->start_time);
410
411         /* seconds between sending first and last DISCOVER
412          * must always be strictly positive to deal with broken servers */
413         client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
414
415         r = client_message_init(client, &discover, DHCP_DISCOVER,
416                                 &optlen, &optoffset);
417         if (r < 0)
418                 return r;
419
420         /* the client may suggest values for the network address
421            and lease time in the DHCPDISCOVER message. The client may include
422            the ’requested IP address’ option to suggest that a particular IP
423            address be assigned, and may include the ’IP address lease time’
424            option to suggest the lease time it would like.
425          */
426         if (client->last_addr != INADDR_ANY) {
427                 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
428                                        DHCP_OPTION_REQUESTED_IP_ADDRESS,
429                                        4, &client->last_addr);
430                 if (r < 0)
431                         return r;
432         }
433
434         /* it is unclear from RFC 2131 if client should send hostname in
435            DHCPDISCOVER but dhclient does and so we do as well
436         */
437         if (client->hostname) {
438                 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
439                                        DHCP_OPTION_HOST_NAME,
440                                        strlen(client->hostname), client->hostname);
441                 if (r < 0)
442                         return r;
443         }
444
445         if (client->vendor_class_identifier) {
446                 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
447                                        DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
448                                        strlen(client->vendor_class_identifier),
449                                        client->vendor_class_identifier);
450                 if (r < 0)
451                         return r;
452         }
453
454         r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
455                                DHCP_OPTION_END, 0, NULL);
456         if (r < 0)
457                 return r;
458
459         /* We currently ignore:
460            The client SHOULD wait a random time between one and ten seconds to
461            desynchronize the use of DHCP at startup.
462          */
463         r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
464         if (r < 0)
465                 return r;
466
467         log_dhcp_client(client, "DISCOVER");
468
469         return 0;
470 }
471
472 static int client_send_request(sd_dhcp_client *client) {
473         _cleanup_free_ DHCPPacket *request = NULL;
474         size_t optoffset, optlen;
475         int r;
476
477         r = client_message_init(client, &request, DHCP_REQUEST,
478                                 &optlen, &optoffset);
479         if (r < 0)
480                 return r;
481
482         switch (client->state) {
483         /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
484            SELECTING should be REQUESTING)
485          */
486
487         case DHCP_STATE_REQUESTING:
488                 /* Client inserts the address of the selected server in ’server
489                    identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
490                    filled in with the yiaddr value from the chosen DHCPOFFER.
491                  */
492
493                 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
494                                        DHCP_OPTION_SERVER_IDENTIFIER,
495                                        4, &client->lease->server_address);
496                 if (r < 0)
497                         return r;
498
499                 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
500                                        DHCP_OPTION_REQUESTED_IP_ADDRESS,
501                                        4, &client->lease->address);
502                 if (r < 0)
503                         return r;
504
505                 break;
506
507         case DHCP_STATE_INIT_REBOOT:
508                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
509                    option MUST be filled in with client’s notion of its previously
510                    assigned address. ’ciaddr’ MUST be zero.
511                  */
512                 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
513                                        DHCP_OPTION_REQUESTED_IP_ADDRESS,
514                                        4, &client->last_addr);
515                 if (r < 0)
516                         return r;
517                 break;
518
519         case DHCP_STATE_RENEWING:
520                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
521                    option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
522                    client’s IP address.
523                 */
524
525                 /* fall through */
526         case DHCP_STATE_REBINDING:
527                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
528                    option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
529                    client’s IP address.
530
531                    This message MUST be broadcast to the 0xffffffff IP broadcast address.
532                  */
533                 request->dhcp.ciaddr = client->lease->address;
534
535                 break;
536
537         case DHCP_STATE_INIT:
538         case DHCP_STATE_SELECTING:
539         case DHCP_STATE_REBOOTING:
540         case DHCP_STATE_BOUND:
541         case DHCP_STATE_STOPPED:
542                 return -EINVAL;
543         }
544
545         if (client->hostname) {
546                 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
547                                        DHCP_OPTION_HOST_NAME,
548                                        strlen(client->hostname), client->hostname);
549                 if (r < 0)
550                         return r;
551         }
552
553         r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
554                                DHCP_OPTION_END, 0, NULL);
555         if (r < 0)
556                 return r;
557
558         if (client->state == DHCP_STATE_RENEWING) {
559                 r = dhcp_network_send_udp_socket(client->fd,
560                                                  client->lease->server_address,
561                                                  DHCP_PORT_SERVER,
562                                                  &request->dhcp,
563                                                  sizeof(DHCPMessage) + optoffset);
564         } else {
565                 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
566         }
567         if (r < 0)
568                 return r;
569
570         switch (client->state) {
571         case DHCP_STATE_REQUESTING:
572                 log_dhcp_client(client, "REQUEST (requesting)");
573                 break;
574         case DHCP_STATE_INIT_REBOOT:
575                 log_dhcp_client(client, "REQUEST (init-reboot)");
576                 break;
577         case DHCP_STATE_RENEWING:
578                 log_dhcp_client(client, "REQUEST (renewing)");
579                 break;
580         case DHCP_STATE_REBINDING:
581                 log_dhcp_client(client, "REQUEST (rebinding)");
582                 break;
583         default:
584                 log_dhcp_client(client, "REQUEST (invalid)");
585                 break;
586         }
587
588         return 0;
589 }
590
591 static int client_start(sd_dhcp_client *client);
592
593 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
594                                  void *userdata) {
595         sd_dhcp_client *client = userdata;
596         DHCP_CLIENT_DONT_DESTROY(client);
597         usec_t next_timeout = 0;
598         uint64_t time_now;
599         uint32_t time_left;
600         int r;
601
602         assert(s);
603         assert(client);
604         assert(client->event);
605
606         r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
607         if (r < 0)
608                 goto error;
609
610         switch (client->state) {
611         case DHCP_STATE_RENEWING:
612
613                 time_left = (client->lease->t2 - client->lease->t1) / 2;
614                 if (time_left < 60)
615                         time_left = 60;
616
617                 next_timeout = time_now + time_left * USEC_PER_SEC;
618
619                 break;
620
621         case DHCP_STATE_REBINDING:
622
623                 time_left = (client->lease->lifetime - client->lease->t2) / 2;
624                 if (time_left < 60)
625                         time_left = 60;
626
627                 next_timeout = time_now + time_left * USEC_PER_SEC;
628                 break;
629
630         case DHCP_STATE_REBOOTING:
631                 /* start over as we did not receive a timely ack or nak */
632                 r = client_initialize(client);
633                 if (r < 0)
634                         goto error;
635
636                 r = client_start(client);
637                 if (r < 0)
638                         goto error;
639                 else {
640                         log_dhcp_client(client, "REBOOTED");
641                         return 0;
642                 }
643
644         case DHCP_STATE_INIT:
645         case DHCP_STATE_INIT_REBOOT:
646         case DHCP_STATE_SELECTING:
647         case DHCP_STATE_REQUESTING:
648         case DHCP_STATE_BOUND:
649
650                 if (client->attempt < 64)
651                         client->attempt *= 2;
652
653                 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
654
655                 break;
656
657         case DHCP_STATE_STOPPED:
658                 r = -EINVAL;
659                 goto error;
660         }
661
662         next_timeout += (random_u32() & 0x1fffff);
663
664         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
665
666         r = sd_event_add_time(client->event,
667                               &client->timeout_resend,
668                               clock_boottime_or_monotonic(),
669                               next_timeout, 10 * USEC_PER_MSEC,
670                               client_timeout_resend, client);
671         if (r < 0)
672                 goto error;
673
674         r = sd_event_source_set_priority(client->timeout_resend,
675                                          client->event_priority);
676         if (r < 0)
677                 goto error;
678
679         switch (client->state) {
680         case DHCP_STATE_INIT:
681                 r = client_send_discover(client);
682                 if (r >= 0) {
683                         client->state = DHCP_STATE_SELECTING;
684                         client->attempt = 1;
685                 } else {
686                         if (client->attempt >= 64)
687                                 goto error;
688                 }
689
690                 break;
691
692         case DHCP_STATE_SELECTING:
693                 r = client_send_discover(client);
694                 if (r < 0 && client->attempt >= 64)
695                         goto error;
696
697                 break;
698
699         case DHCP_STATE_INIT_REBOOT:
700         case DHCP_STATE_REQUESTING:
701         case DHCP_STATE_RENEWING:
702         case DHCP_STATE_REBINDING:
703                 r = client_send_request(client);
704                 if (r < 0 && client->attempt >= 64)
705                          goto error;
706
707                 if (client->state == DHCP_STATE_INIT_REBOOT)
708                         client->state = DHCP_STATE_REBOOTING;
709
710                 client->request_sent = time_now;
711
712                 break;
713
714         case DHCP_STATE_REBOOTING:
715         case DHCP_STATE_BOUND:
716
717                 break;
718
719         case DHCP_STATE_STOPPED:
720                 r = -EINVAL;
721                 goto error;
722         }
723
724         return 0;
725
726 error:
727         client_stop(client, r);
728
729         /* Errors were dealt with when stopping the client, don't spill
730            errors into the event loop handler */
731         return 0;
732 }
733
734 static int client_initialize_io_events(sd_dhcp_client *client,
735                                        sd_event_io_handler_t io_callback) {
736         int r;
737
738         assert(client);
739         assert(client->event);
740
741         r = sd_event_add_io(client->event, &client->receive_message,
742                             client->fd, EPOLLIN, io_callback,
743                             client);
744         if (r < 0)
745                 goto error;
746
747         r = sd_event_source_set_priority(client->receive_message,
748                                          client->event_priority);
749         if (r < 0)
750                 goto error;
751
752 error:
753         if (r < 0)
754                 client_stop(client, r);
755
756         return 0;
757 }
758
759 static int client_initialize_time_events(sd_dhcp_client *client) {
760         int r;
761
762         assert(client);
763         assert(client->event);
764
765         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
766
767         r = sd_event_add_time(client->event,
768                               &client->timeout_resend,
769                               clock_boottime_or_monotonic(),
770                               0, 0,
771                               client_timeout_resend, client);
772         if (r < 0)
773                 goto error;
774
775         r = sd_event_source_set_priority(client->timeout_resend,
776                                          client->event_priority);
777
778 error:
779         if (r < 0)
780                 client_stop(client, r);
781
782         return 0;
783
784 }
785
786 static int client_initialize_events(sd_dhcp_client *client,
787                                     sd_event_io_handler_t io_callback) {
788         client_initialize_io_events(client, io_callback);
789         client_initialize_time_events(client);
790
791         return 0;
792 }
793
794 static int client_start(sd_dhcp_client *client) {
795         int r;
796
797         assert_return(client, -EINVAL);
798         assert_return(client->event, -EINVAL);
799         assert_return(client->index > 0, -EINVAL);
800         assert_return(client->fd < 0, -EBUSY);
801         assert_return(client->xid == 0, -EINVAL);
802         assert_return(client->state == DHCP_STATE_INIT ||
803                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
804
805         client->xid = random_u32();
806
807         r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
808         if (r < 0) {
809                 client_stop(client, r);
810                 return r;
811         }
812         client->fd = r;
813
814         if (client->state == DHCP_STATE_INIT) {
815                 client->start_time = now(clock_boottime_or_monotonic());
816                 client->secs = 0;
817         }
818
819         return client_initialize_events(client, client_receive_message_raw);
820 }
821
822 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
823                                  void *userdata) {
824         sd_dhcp_client *client = userdata;
825         DHCP_CLIENT_DONT_DESTROY(client);
826
827         log_dhcp_client(client, "EXPIRED");
828
829         client_notify(client, DHCP_EVENT_EXPIRED);
830
831         /* lease was lost, start over if not freed or stopped in callback */
832         if (client->state != DHCP_STATE_STOPPED) {
833                 client_initialize(client);
834                 client_start(client);
835         }
836
837         return 0;
838 }
839
840 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
841         sd_dhcp_client *client = userdata;
842         DHCP_CLIENT_DONT_DESTROY(client);
843         int r;
844
845         client->receive_message = sd_event_source_unref(client->receive_message);
846         client->fd = asynchronous_close(client->fd);
847
848         client->state = DHCP_STATE_REBINDING;
849         client->attempt = 1;
850
851         r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
852         if (r < 0) {
853                 client_stop(client, r);
854                 return 0;
855         }
856         client->fd = r;
857
858         return client_initialize_events(client, client_receive_message_raw);
859 }
860
861 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
862                              void *userdata) {
863         sd_dhcp_client *client = userdata;
864         DHCP_CLIENT_DONT_DESTROY(client);
865
866         client->state = DHCP_STATE_RENEWING;
867         client->attempt = 1;
868
869         return client_initialize_time_events(client);
870 }
871
872 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
873                                size_t len) {
874         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
875         int r;
876
877         r = dhcp_lease_new(&lease);
878         if (r < 0)
879                 return r;
880
881         r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
882         if (r != DHCP_OFFER) {
883                 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
884                 return -ENOMSG;
885         }
886
887         lease->next_server = offer->siaddr;
888
889         lease->address = offer->yiaddr;
890
891         if (lease->address == INADDR_ANY ||
892             lease->server_address == INADDR_ANY ||
893             lease->lifetime == 0) {
894                 log_dhcp_client(client, "receieved lease lacks address, server "
895                                 "address or lease lifetime, ignoring");
896                 return -ENOMSG;
897         }
898
899         if (lease->subnet_mask == INADDR_ANY) {
900                 r = dhcp_lease_set_default_subnet_mask(lease);
901                 if (r < 0) {
902                         log_dhcp_client(client, "receieved lease lacks subnet "
903                                         "mask, and a fallback one can not be "
904                                         "generated, ignoring");
905                         return -ENOMSG;
906                 }
907         }
908
909         sd_dhcp_lease_unref(client->lease);
910         client->lease = lease;
911         lease = NULL;
912
913         log_dhcp_client(client, "OFFER");
914
915         return 0;
916 }
917
918 static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
919                                     size_t len) {
920         int r;
921
922         r = dhcp_option_parse(force, len, NULL, NULL);
923         if (r != DHCP_FORCERENEW)
924                 return -ENOMSG;
925
926         log_dhcp_client(client, "FORCERENEW");
927
928         return 0;
929 }
930
931 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
932                              size_t len) {
933         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
934         int r;
935
936         r = dhcp_lease_new(&lease);
937         if (r < 0)
938                 return r;
939
940         r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
941         if (r == DHCP_NAK) {
942                 log_dhcp_client(client, "NAK");
943                 return -EADDRNOTAVAIL;
944         }
945
946         if (r != DHCP_ACK) {
947                 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
948                 return -ENOMSG;
949         }
950
951         lease->next_server = ack->siaddr;
952
953         lease->address = ack->yiaddr;
954
955         if (lease->address == INADDR_ANY ||
956             lease->server_address == INADDR_ANY ||
957             lease->lifetime == 0) {
958                 log_dhcp_client(client, "receieved lease lacks address, server "
959                                 "address or lease lifetime, ignoring");
960                 return -ENOMSG;
961         }
962
963         if (lease->subnet_mask == INADDR_ANY) {
964                 r = dhcp_lease_set_default_subnet_mask(lease);
965                 if (r < 0) {
966                         log_dhcp_client(client, "receieved lease lacks subnet "
967                                         "mask, and a fallback one can not be "
968                                         "generated, ignoring");
969                         return -ENOMSG;
970                 }
971         }
972
973         r = DHCP_EVENT_IP_ACQUIRE;
974         if (client->lease) {
975                 if (client->lease->address != lease->address ||
976                     client->lease->subnet_mask != lease->subnet_mask ||
977                     client->lease->router != lease->router) {
978                         r = DHCP_EVENT_IP_CHANGE;
979                 } else
980                         r = DHCP_EVENT_RENEW;
981
982                 client->lease = sd_dhcp_lease_unref(client->lease);
983         }
984
985         client->lease = lease;
986         lease = NULL;
987
988         log_dhcp_client(client, "ACK");
989
990         return r;
991 }
992
993 static uint64_t client_compute_timeout(sd_dhcp_client *client,
994                                        uint32_t lifetime, double factor) {
995         assert(client);
996         assert(client->request_sent);
997         assert(lifetime);
998
999         return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
1000                 + (random_u32() & 0x1fffff);
1001 }
1002
1003 static int client_set_lease_timeouts(sd_dhcp_client *client) {
1004         usec_t time_now;
1005         uint64_t lifetime_timeout;
1006         uint64_t t2_timeout;
1007         uint64_t t1_timeout;
1008         char time_string[FORMAT_TIMESPAN_MAX];
1009         int r;
1010
1011         assert(client);
1012         assert(client->event);
1013         assert(client->lease);
1014         assert(client->lease->lifetime);
1015
1016         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1017         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1018         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
1019
1020         /* don't set timers for infinite leases */
1021         if (client->lease->lifetime == 0xffffffff)
1022                 return 0;
1023
1024         r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1025         if (r < 0)
1026                 return r;
1027         assert(client->request_sent <= time_now);
1028
1029         /* convert the various timeouts from relative (secs) to absolute (usecs) */
1030         lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
1031         if (client->lease->t1 && client->lease->t2) {
1032                 /* both T1 and T2 are given */
1033                 if (client->lease->t1 < client->lease->t2 &&
1034                     client->lease->t2 < client->lease->lifetime) {
1035                         /* they are both valid */
1036                         t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1037                         t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1038                 } else {
1039                         /* discard both */
1040                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1041                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
1042                         t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1043                         client->lease->t1 = client->lease->lifetime / 2;
1044                 }
1045         } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
1046                 /* only T2 is given, and it is valid */
1047                 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1048                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1049                 client->lease->t1 = client->lease->lifetime / 2;
1050                 if (t2_timeout <= t1_timeout) {
1051                         /* the computed T1 would be invalid, so discard T2 */
1052                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1053                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
1054                 }
1055         } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
1056                 /* only T1 is given, and it is valid */
1057                 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1058                 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1059                 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1060                 if (t2_timeout <= t1_timeout) {
1061                         /* the computed T2 would be invalid, so discard T1 */
1062                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1063                         client->lease->t2 = client->lease->lifetime / 2;
1064                 }
1065         } else {
1066                 /* fall back to the default timeouts */
1067                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1068                 client->lease->t1 = client->lease->lifetime / 2;
1069                 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1070                 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1071         }
1072
1073         /* arm lifetime timeout */
1074         r = sd_event_add_time(client->event, &client->timeout_expire,
1075                               clock_boottime_or_monotonic(),
1076                               lifetime_timeout, 10 * USEC_PER_MSEC,
1077                               client_timeout_expire, client);
1078         if (r < 0)
1079                 return r;
1080
1081         r = sd_event_source_set_priority(client->timeout_expire,
1082                                          client->event_priority);
1083         if (r < 0)
1084                 return r;
1085
1086         log_dhcp_client(client, "lease expires in %s",
1087                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1088                         lifetime_timeout - time_now, 0));
1089
1090         /* don't arm earlier timeouts if this has already expired */
1091         if (lifetime_timeout <= time_now)
1092                 return 0;
1093
1094         /* arm T2 timeout */
1095         r = sd_event_add_time(client->event,
1096                               &client->timeout_t2,
1097                               clock_boottime_or_monotonic(),
1098                               t2_timeout,
1099                               10 * USEC_PER_MSEC,
1100                               client_timeout_t2, client);
1101         if (r < 0)
1102                 return r;
1103
1104         r = sd_event_source_set_priority(client->timeout_t2,
1105                                          client->event_priority);
1106         if (r < 0)
1107                 return r;
1108
1109         log_dhcp_client(client, "T2 expires in %s",
1110                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1111                         t2_timeout - time_now, 0));
1112
1113         /* don't arm earlier timeout if this has already expired */
1114         if (t2_timeout <= time_now)
1115                 return 0;
1116
1117         /* arm T1 timeout */
1118         r = sd_event_add_time(client->event,
1119                               &client->timeout_t1,
1120                               clock_boottime_or_monotonic(),
1121                               t1_timeout, 10 * USEC_PER_MSEC,
1122                               client_timeout_t1, client);
1123         if (r < 0)
1124                 return r;
1125
1126         r = sd_event_source_set_priority(client->timeout_t1,
1127                                          client->event_priority);
1128         if (r < 0)
1129                 return r;
1130
1131         log_dhcp_client(client, "T1 expires in %s",
1132                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1133                         t1_timeout - time_now, 0));
1134
1135         return 0;
1136 }
1137
1138 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1139                                  int len) {
1140         DHCP_CLIENT_DONT_DESTROY(client);
1141         int r = 0, notify_event = 0;
1142
1143         assert(client);
1144         assert(client->event);
1145         assert(message);
1146
1147         switch (client->state) {
1148         case DHCP_STATE_SELECTING:
1149
1150                 r = client_handle_offer(client, message, len);
1151                 if (r >= 0) {
1152
1153                         client->timeout_resend =
1154                                 sd_event_source_unref(client->timeout_resend);
1155
1156                         client->state = DHCP_STATE_REQUESTING;
1157                         client->attempt = 1;
1158
1159                         r = sd_event_add_time(client->event,
1160                                               &client->timeout_resend,
1161                                               clock_boottime_or_monotonic(),
1162                                               0, 0,
1163                                               client_timeout_resend, client);
1164                         if (r < 0)
1165                                 goto error;
1166
1167                         r = sd_event_source_set_priority(client->timeout_resend,
1168                                                          client->event_priority);
1169                         if (r < 0)
1170                                 goto error;
1171                 } else if (r == -ENOMSG)
1172                         /* invalid message, let's ignore it */
1173                         return 0;
1174
1175                 break;
1176
1177         case DHCP_STATE_REBOOTING:
1178         case DHCP_STATE_REQUESTING:
1179         case DHCP_STATE_RENEWING:
1180         case DHCP_STATE_REBINDING:
1181
1182                 r = client_handle_ack(client, message, len);
1183                 if (r >= 0) {
1184                         client->timeout_resend =
1185                                 sd_event_source_unref(client->timeout_resend);
1186
1187                         if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1188                                    DHCP_STATE_REBOOTING))
1189                                 notify_event = DHCP_EVENT_IP_ACQUIRE;
1190                         else if (r != DHCP_EVENT_IP_ACQUIRE)
1191                                 notify_event = r;
1192
1193                         client->state = DHCP_STATE_BOUND;
1194                         client->attempt = 1;
1195
1196                         client->last_addr = client->lease->address;
1197
1198                         r = client_set_lease_timeouts(client);
1199                         if (r < 0)
1200                                 goto error;
1201
1202                         r = dhcp_network_bind_udp_socket(client->lease->address,
1203                                                          DHCP_PORT_CLIENT);
1204                         if (r < 0) {
1205                                 log_dhcp_client(client, "could not bind UDP socket");
1206                                 goto error;
1207                         }
1208
1209                         client->fd = r;
1210
1211                         client_initialize_io_events(client, client_receive_message_udp);
1212
1213                         if (notify_event) {
1214                                 client_notify(client, notify_event);
1215                                 if (client->state == DHCP_STATE_STOPPED)
1216                                         return 0;
1217                         }
1218
1219                 } else if (r == -EADDRNOTAVAIL) {
1220                         /* got a NAK, let's restart the client */
1221                         client->timeout_resend =
1222                                 sd_event_source_unref(client->timeout_resend);
1223
1224                         r = client_initialize(client);
1225                         if (r < 0)
1226                                 goto error;
1227
1228                         r = client_start(client);
1229                         if (r < 0)
1230                                 goto error;
1231
1232                         log_dhcp_client(client, "REBOOTED");
1233
1234                         return 0;
1235                 } else if (r == -ENOMSG)
1236                         /* invalid message, let's ignore it */
1237                         return 0;
1238
1239                 break;
1240
1241         case DHCP_STATE_BOUND:
1242                 r = client_handle_forcerenew(client, message, len);
1243                 if (r >= 0) {
1244                         r = client_timeout_t1(NULL, 0, client);
1245                         if (r < 0)
1246                                 goto error;
1247                 } else if (r == -ENOMSG)
1248                         /* invalid message, let's ignore it */
1249                         return 0;
1250
1251                 break;
1252
1253         case DHCP_STATE_INIT:
1254         case DHCP_STATE_INIT_REBOOT:
1255
1256                 break;
1257
1258         case DHCP_STATE_STOPPED:
1259                 r = -EINVAL;
1260                 goto error;
1261         }
1262
1263 error:
1264         if (r < 0)
1265                 client_stop(client, r);
1266
1267         return r;
1268 }
1269
1270 static int client_receive_message_udp(sd_event_source *s, int fd,
1271                                       uint32_t revents, void *userdata) {
1272         sd_dhcp_client *client = userdata;
1273         _cleanup_free_ DHCPMessage *message = NULL;
1274         int buflen = 0, len, r;
1275
1276         assert(s);
1277         assert(client);
1278
1279         r = ioctl(fd, FIONREAD, &buflen);
1280         if (r < 0)
1281                 return r;
1282
1283         if (buflen < 0)
1284                 /* this can't be right */
1285                 return -EIO;
1286
1287         message = malloc0(buflen);
1288         if (!message)
1289                 return -ENOMEM;
1290
1291         len = read(fd, message, buflen);
1292         if (len < 0) {
1293                 log_dhcp_client(client, "could not receive message from UDP "
1294                                 "socket: %m");
1295                 return 0;
1296         } else if ((size_t)len < sizeof(DHCPMessage)) {
1297                 log_dhcp_client(client, "too small to be a DHCP message: ignoring");
1298                 return 0;
1299         }
1300
1301         if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1302                 log_dhcp_client(client, "not a DHCP message: ignoring");
1303                 return 0;
1304         }
1305
1306         if (message->op != BOOTREPLY) {
1307                 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1308                 return 0;
1309         }
1310
1311         if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1312                 log_dhcp_client(client, "not an ethernet packet");
1313                 return 0;
1314         }
1315
1316         if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1317                    ETH_ALEN)) {
1318                 log_dhcp_client(client, "received chaddr does not match "
1319                                 "expected: ignoring");
1320                 return 0;
1321         }
1322
1323         if (client->state != DHCP_STATE_BOUND &&
1324             be32toh(message->xid) != client->xid) {
1325                 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1326                    so ignore the xid in this case */
1327                 log_dhcp_client(client, "received xid (%u) does not match "
1328                                 "expected (%u): ignoring",
1329                                 be32toh(message->xid), client->xid);
1330                 return 0;
1331         }
1332
1333         return client_handle_message(client, message, len);
1334 }
1335
1336 static int client_receive_message_raw(sd_event_source *s, int fd,
1337                                       uint32_t revents, void *userdata) {
1338         sd_dhcp_client *client = userdata;
1339         _cleanup_free_ DHCPPacket *packet = NULL;
1340         uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1341         struct iovec iov = {};
1342         struct msghdr msg = {
1343                 .msg_iov = &iov,
1344                 .msg_iovlen = 1,
1345                 .msg_control = cmsgbuf,
1346                 .msg_controllen = sizeof(cmsgbuf),
1347         };
1348         struct cmsghdr *cmsg;
1349         bool checksum = true;
1350         int buflen = 0, len, r;
1351
1352         assert(s);
1353         assert(client);
1354
1355         r = ioctl(fd, FIONREAD, &buflen);
1356         if (r < 0)
1357                 return r;
1358
1359         if (buflen < 0)
1360                 /* this can't be right */
1361                 return -EIO;
1362
1363         packet = malloc0(buflen);
1364         if (!packet)
1365                 return -ENOMEM;
1366
1367         iov.iov_base = packet;
1368         iov.iov_len = buflen;
1369
1370         len = recvmsg(fd, &msg, 0);
1371         if (len < 0) {
1372                 log_dhcp_client(client, "could not receive message from raw "
1373                                 "socket: %m");
1374                 return 0;
1375         } else if ((size_t)len < sizeof(DHCPPacket))
1376                 return 0;
1377
1378         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1379                 if (cmsg->cmsg_level == SOL_PACKET &&
1380                     cmsg->cmsg_type == PACKET_AUXDATA &&
1381                     cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1382                         struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1383
1384                         checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1385                         break;
1386                 }
1387         }
1388
1389         r = dhcp_packet_verify_headers(packet, len, checksum);
1390         if (r < 0)
1391                 return 0;
1392
1393         len -= DHCP_IP_UDP_SIZE;
1394
1395         return client_handle_message(client, &packet->dhcp, len);
1396 }
1397
1398 int sd_dhcp_client_start(sd_dhcp_client *client) {
1399         int r;
1400
1401         assert_return(client, -EINVAL);
1402
1403         r = client_initialize(client);
1404         if (r < 0)
1405                 return r;
1406
1407         if (client->last_addr)
1408                 client->state = DHCP_STATE_INIT_REBOOT;
1409
1410         r = client_start(client);
1411         if (r >= 0)
1412                 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1413                                 client->index,
1414                                 ether_ntoa(&client->client_id.mac_addr));
1415
1416         return r;
1417 }
1418
1419 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1420         DHCP_CLIENT_DONT_DESTROY(client);
1421
1422         assert_return(client, -EINVAL);
1423
1424         client_stop(client, DHCP_EVENT_STOP);
1425         client->state = DHCP_STATE_STOPPED;
1426
1427         return 0;
1428 }
1429
1430 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1431                                 int priority) {
1432         int r;
1433
1434         assert_return(client, -EINVAL);
1435         assert_return(!client->event, -EBUSY);
1436
1437         if (event)
1438                 client->event = sd_event_ref(event);
1439         else {
1440                 r = sd_event_default(&client->event);
1441                 if (r < 0)
1442                         return 0;
1443         }
1444
1445         client->event_priority = priority;
1446
1447         return 0;
1448 }
1449
1450 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1451         assert_return(client, -EINVAL);
1452
1453         client->event = sd_event_unref(client->event);
1454
1455         return 0;
1456 }
1457
1458 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1459         if (!client)
1460                 return NULL;
1461
1462         return client->event;
1463 }
1464
1465 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1466         if (client)
1467                 assert_se(REFCNT_INC(client->n_ref) >= 2);
1468
1469         return client;
1470 }
1471
1472 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1473         if (client && REFCNT_DEC(client->n_ref) <= 0) {
1474                 log_dhcp_client(client, "FREE");
1475
1476                 client_initialize(client);
1477
1478                 client->receive_message =
1479                         sd_event_source_unref(client->receive_message);
1480
1481                 sd_dhcp_client_detach_event(client);
1482
1483                 sd_dhcp_lease_unref(client->lease);
1484
1485                 free(client->req_opts);
1486                 free(client->hostname);
1487                 free(client->vendor_class_identifier);
1488                 free(client);
1489         }
1490
1491         return NULL;
1492 }
1493
1494 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1495         _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1496
1497         assert_return(ret, -EINVAL);
1498
1499         client = new0(sd_dhcp_client, 1);
1500         if (!client)
1501                 return -ENOMEM;
1502
1503         client->n_ref = REFCNT_INIT;
1504         client->state = DHCP_STATE_INIT;
1505         client->index = -1;
1506         client->fd = -1;
1507         client->attempt = 1;
1508
1509         client->req_opts_size = ELEMENTSOF(default_req_opts);
1510
1511         client->req_opts = memdup(default_req_opts, client->req_opts_size);
1512         if (!client->req_opts)
1513                 return -ENOMEM;
1514
1515         *ret = client;
1516         client = NULL;
1517
1518         return 0;
1519 }