chiark / gitweb /
resolved: properly process SRV records
[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 }