2 This file is part of systemd.
4 Copyright (C) 2013 Intel Corporation. All rights reserved.
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.
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.
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/>.
24 #include <net/ethernet.h>
25 #include <sys/param.h>
26 #include <sys/ioctl.h>
31 #include "dhcp-protocol.h"
32 #include "dhcp-lease.h"
33 #include "dhcp-internal.h"
34 #include "sd-dhcp-client.h"
36 struct sd_dhcp_client
{
40 sd_event_source
*timeout_resend
;
43 union sockaddr_union link
;
44 sd_event_source
*receive_message
;
46 size_t req_opts_allocated
;
49 struct ether_addr mac_addr
;
55 sd_event_source
*timeout_t1
;
56 sd_event_source
*timeout_t2
;
57 sd_event_source
*timeout_expire
;
58 sd_dhcp_client_cb_t cb
;
63 static const uint8_t default_req_opts
[] = {
64 DHCP_OPTION_SUBNET_MASK
,
66 DHCP_OPTION_HOST_NAME
,
67 DHCP_OPTION_DOMAIN_NAME
,
68 DHCP_OPTION_DOMAIN_NAME_SERVER
,
69 DHCP_OPTION_NTP_SERVER
,
72 static int client_receive_message_raw(sd_event_source
*s
, int fd
,
73 uint32_t revents
, void *userdata
);
74 static int client_receive_message_udp(sd_event_source
*s
, int fd
,
75 uint32_t revents
, void *userdata
);
77 int sd_dhcp_client_set_callback(sd_dhcp_client
*client
, sd_dhcp_client_cb_t cb
,
79 assert_return(client
, -EINVAL
);
82 client
->userdata
= userdata
;
87 int sd_dhcp_client_set_request_option(sd_dhcp_client
*client
, uint8_t option
) {
90 assert_return(client
, -EINVAL
);
91 assert_return (client
->state
== DHCP_STATE_INIT
, -EBUSY
);
95 case DHCP_OPTION_OVERLOAD
:
96 case DHCP_OPTION_MESSAGE_TYPE
:
97 case DHCP_OPTION_PARAMETER_REQUEST_LIST
:
105 for (i
= 0; i
< client
->req_opts_size
; i
++)
106 if (client
->req_opts
[i
] == option
)
109 if (!GREEDY_REALLOC(client
->req_opts
, client
->req_opts_allocated
,
110 client
->req_opts_size
+ 1))
113 client
->req_opts
[client
->req_opts_size
++] = option
;
118 int sd_dhcp_client_set_request_address(sd_dhcp_client
*client
,
119 const struct in_addr
*last_addr
) {
120 assert_return(client
, -EINVAL
);
121 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
124 client
->last_addr
= last_addr
->s_addr
;
126 client
->last_addr
= INADDR_ANY
;
131 int sd_dhcp_client_set_index(sd_dhcp_client
*client
, int interface_index
) {
132 assert_return(client
, -EINVAL
);
133 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
134 assert_return(interface_index
>= -1, -EINVAL
);
136 client
->index
= interface_index
;
141 int sd_dhcp_client_set_mac(sd_dhcp_client
*client
,
142 const struct ether_addr
*addr
) {
143 assert_return(client
, -EINVAL
);
144 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
146 memcpy(&client
->mac_addr
, addr
, ETH_ALEN
);
151 int sd_dhcp_client_get_lease(sd_dhcp_client
*client
, sd_dhcp_lease
**ret
) {
152 assert_return(client
, -EINVAL
);
153 assert_return(ret
, -EINVAL
);
155 if (client
->state
!= DHCP_STATE_BOUND
&&
156 client
->state
!= DHCP_STATE_RENEWING
&&
157 client
->state
!= DHCP_STATE_REBINDING
)
158 return -EADDRNOTAVAIL
;
160 *ret
= sd_dhcp_lease_ref(client
->lease
);
165 static int client_notify(sd_dhcp_client
*client
, int event
) {
167 client
->cb(client
, event
, client
->userdata
);
172 static int client_stop(sd_dhcp_client
*client
, int error
) {
173 assert_return(client
, -EINVAL
);
175 client
->receive_message
=
176 sd_event_source_unref(client
->receive_message
);
182 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
184 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
185 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
186 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
190 client_notify(client
, error
);
192 client
->start_time
= 0;
194 client
->state
= DHCP_STATE_INIT
;
197 client
->lease
= sd_dhcp_lease_unref(client
->lease
);
199 log_dhcp_client(client
, "STOPPED");
204 static int client_message_init(sd_dhcp_client
*client
, DHCPMessage
*message
,
205 uint8_t type
, uint16_t secs
, uint8_t **opt
,
211 r
= dhcp_message_init(message
, BOOTREQUEST
, client
->xid
, type
, opt
,
216 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
217 refuse to issue an DHCP lease if 'secs' is set to zero */
218 message
->secs
= htobe16(secs
);
220 memcpy(&message
->chaddr
, &client
->mac_addr
, ETH_ALEN
);
222 if (client
->state
== DHCP_STATE_RENEWING
||
223 client
->state
== DHCP_STATE_REBINDING
)
224 message
->ciaddr
= client
->lease
->address
;
226 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
227 Identifier option is not set */
228 r
= dhcp_option_append(opt
, optlen
, DHCP_OPTION_CLIENT_IDENTIFIER
,
229 ETH_ALEN
, &client
->mac_addr
);
233 if (type
== DHCP_DISCOVER
|| type
== DHCP_REQUEST
) {
236 r
= dhcp_option_append(opt
, optlen
,
237 DHCP_OPTION_PARAMETER_REQUEST_LIST
,
238 client
->req_opts_size
,
243 /* Some DHCP servers will send bigger DHCP packets than the
244 defined default size unless the Maximum Messge Size option
245 is explicitely set */
246 max_size
= htobe16(DHCP_IP_UDP_SIZE
+ DHCP_MESSAGE_SIZE
+
247 DHCP_MIN_OPTIONS_SIZE
);
248 r
= dhcp_option_append(opt
, optlen
,
249 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
,
258 static int client_send_discover(sd_dhcp_client
*client
, uint16_t secs
) {
260 _cleanup_free_ DHCPPacket
*discover
;
264 optlen
= DHCP_MIN_OPTIONS_SIZE
;
265 len
= sizeof(DHCPPacket
) + optlen
;
267 discover
= malloc0(len
);
272 err
= client_message_init(client
, &discover
->dhcp
, DHCP_DISCOVER
,
273 secs
, &opt
, &optlen
);
277 if (client
->last_addr
!= INADDR_ANY
) {
278 err
= dhcp_option_append(&opt
, &optlen
,
279 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
280 4, &client
->last_addr
);
285 err
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
289 dhcp_packet_append_ip_headers(discover
, len
);
291 err
= dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
294 log_dhcp_client(client
, "DISCOVER");
299 static int client_send_request(sd_dhcp_client
*client
, uint16_t secs
) {
300 _cleanup_free_ DHCPPacket
*request
;
305 optlen
= DHCP_MIN_OPTIONS_SIZE
;
306 len
= sizeof(DHCPPacket
) + optlen
;
308 request
= malloc0(len
);
312 err
= client_message_init(client
, &request
->dhcp
, DHCP_REQUEST
, secs
,
317 if (client
->state
== DHCP_STATE_REQUESTING
) {
318 err
= dhcp_option_append(&opt
, &optlen
,
319 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
320 4, &client
->lease
->address
);
324 err
= dhcp_option_append(&opt
, &optlen
,
325 DHCP_OPTION_SERVER_IDENTIFIER
,
326 4, &client
->lease
->server_address
);
331 err
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
335 if (client
->state
== DHCP_STATE_RENEWING
) {
336 err
= dhcp_network_send_udp_socket(client
->fd
,
337 client
->lease
->server_address
,
340 len
- DHCP_IP_UDP_SIZE
);
342 dhcp_packet_append_ip_headers(request
, len
);
344 err
= dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
348 log_dhcp_client(client
, "REQUEST");
353 static uint16_t client_update_secs(sd_dhcp_client
*client
, usec_t time_now
)
355 client
->secs
= ((time_now
- client
->start_time
) / USEC_PER_SEC
) ? : 1;
360 static int client_timeout_resend(sd_event_source
*s
, uint64_t usec
,
362 sd_dhcp_client
*client
= userdata
;
363 usec_t next_timeout
= 0;
369 assert(client
->event
);
371 switch (client
->state
) {
372 case DHCP_STATE_RENEWING
:
374 time_left
= (client
->lease
->t2
- client
->lease
->t1
) / 2;
378 next_timeout
= usec
+ time_left
* USEC_PER_SEC
;
382 case DHCP_STATE_REBINDING
:
384 time_left
= (client
->lease
->lifetime
- client
->lease
->t2
) / 2;
388 next_timeout
= usec
+ time_left
* USEC_PER_SEC
;
391 case DHCP_STATE_INIT
:
392 case DHCP_STATE_INIT_REBOOT
:
393 case DHCP_STATE_REBOOTING
:
394 case DHCP_STATE_SELECTING
:
395 case DHCP_STATE_REQUESTING
:
396 case DHCP_STATE_BOUND
:
398 if (client
->attempt
< 64)
399 client
->attempt
*= 2;
401 next_timeout
= usec
+ (client
->attempt
- 1) * USEC_PER_SEC
;
406 next_timeout
+= (random_u32() & 0x1fffff);
408 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
410 r
= sd_event_add_monotonic(client
->event
,
411 &client
->timeout_resend
,
414 client_timeout_resend
, client
);
418 r
= sd_event_source_set_priority(client
->timeout_resend
,
419 client
->event_priority
);
423 switch (client
->state
) {
424 case DHCP_STATE_INIT
:
426 client_update_secs(client
, usec
);
428 r
= client_send_discover(client
, client
->secs
);
430 client
->state
= DHCP_STATE_SELECTING
;
433 if (client
->attempt
>= 64)
439 case DHCP_STATE_SELECTING
:
440 client_update_secs(client
, usec
);
442 r
= client_send_discover(client
, client
->secs
);
443 if (r
< 0 && client
->attempt
>= 64)
448 case DHCP_STATE_REQUESTING
:
449 case DHCP_STATE_RENEWING
:
450 case DHCP_STATE_REBINDING
:
451 r
= client_send_request(client
, client
->secs
);
452 if (r
< 0 && client
->attempt
>= 64)
455 client
->request_sent
= usec
;
459 case DHCP_STATE_INIT_REBOOT
:
460 case DHCP_STATE_REBOOTING
:
461 case DHCP_STATE_BOUND
:
469 client_stop(client
, r
);
471 /* Errors were dealt with when stopping the client, don't spill
472 errors into the event loop handler */
476 static int client_initialize_events(sd_dhcp_client
*client
,
477 sd_event_io_handler_t io_callback
,
482 assert(client
->event
);
484 r
= sd_event_add_io(client
->event
, &client
->receive_message
,
485 client
->fd
, EPOLLIN
, io_callback
,
490 r
= sd_event_source_set_priority(client
->receive_message
,
491 client
->event_priority
);
495 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
497 r
= sd_event_add_monotonic(client
->event
,
498 &client
->timeout_resend
,
500 client_timeout_resend
, client
);
504 r
= sd_event_source_set_priority(client
->timeout_resend
,
505 client
->event_priority
);
509 client_stop(client
, r
);
515 static int client_timeout_expire(sd_event_source
*s
, uint64_t usec
,
517 sd_dhcp_client
*client
= userdata
;
519 log_dhcp_client(client
, "EXPIRED");
521 client_stop(client
, DHCP_EVENT_EXPIRED
);
526 static int client_timeout_t2(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
527 sd_dhcp_client
*client
= userdata
;
530 if (client
->fd
>= 0) {
531 client
->receive_message
=
532 sd_event_source_unref(client
->receive_message
);
537 client
->state
= DHCP_STATE_REBINDING
;
540 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
);
542 client_stop(client
, r
);
548 log_dhcp_client(client
, "TIMEOUT T2");
550 return client_initialize_events(client
, client_receive_message_raw
,
554 static int client_timeout_t1(sd_event_source
*s
, uint64_t usec
,
556 sd_dhcp_client
*client
= userdata
;
559 client
->state
= DHCP_STATE_RENEWING
;
562 r
= dhcp_network_bind_udp_socket(client
->index
,
563 client
->lease
->address
,
566 client_stop(client
, r
);
572 log_dhcp_client(client
, "TIMEOUT T1");
574 return client_initialize_events(client
, client_receive_message_udp
, usec
);
577 static int client_handle_offer(sd_dhcp_client
*client
, DHCPMessage
*offer
,
579 _cleanup_dhcp_lease_unref_ sd_dhcp_lease
*lease
= NULL
;
582 r
= dhcp_lease_new(&lease
);
586 r
= dhcp_option_parse(offer
, len
, dhcp_lease_parse_options
, lease
);
590 lease
->address
= offer
->yiaddr
;
592 if (lease
->address
== INADDR_ANY
||
593 lease
->server_address
== INADDR_ANY
||
594 lease
->subnet_mask
== INADDR_ANY
||
595 lease
->lifetime
== 0)
598 client
->lease
= lease
;
601 log_dhcp_client(client
, "OFFER");
606 static int client_handle_ack(sd_dhcp_client
*client
, DHCPMessage
*ack
,
608 _cleanup_dhcp_lease_unref_ sd_dhcp_lease
*lease
= NULL
;
611 r
= dhcp_lease_new(&lease
);
615 r
= dhcp_option_parse(ack
, len
, dhcp_lease_parse_options
, lease
);
617 log_dhcp_client(client
, "NAK");
618 return DHCP_EVENT_NO_LEASE
;
624 lease
->address
= ack
->yiaddr
;
626 if (lease
->address
== INADDR_ANY
||
627 lease
->server_address
== INADDR_ANY
||
628 lease
->subnet_mask
== INADDR_ANY
|| lease
->lifetime
== 0)
631 r
= DHCP_EVENT_IP_ACQUIRE
;
633 if (client
->lease
->address
!= lease
->address
||
634 client
->lease
->subnet_mask
!= lease
->subnet_mask
||
635 client
->lease
->router
!= lease
->router
) {
636 r
= DHCP_EVENT_IP_CHANGE
;
639 client
->lease
= sd_dhcp_lease_unref(client
->lease
);
642 client
->lease
= lease
;
645 log_dhcp_client(client
, "ACK");
650 static uint64_t client_compute_timeout(uint64_t request_sent
,
652 return request_sent
+ (lifetime
- 3) * USEC_PER_SEC
+
653 + (random_u32() & 0x1fffff);
656 static int client_set_lease_timeouts(sd_dhcp_client
*client
, uint64_t usec
) {
657 uint64_t next_timeout
;
661 assert(client
->event
);
663 if (client
->lease
->lifetime
< 10)
666 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
667 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
668 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
670 if (!client
->lease
->t1
)
671 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
673 next_timeout
= client_compute_timeout(client
->request_sent
,
675 if (next_timeout
< usec
)
678 r
= sd_event_add_monotonic(client
->event
,
682 client_timeout_t1
, client
);
686 r
= sd_event_source_set_priority(client
->timeout_t1
,
687 client
->event_priority
);
691 if (!client
->lease
->t2
)
692 client
->lease
->t2
= client
->lease
->lifetime
* 7 / 8;
694 if (client
->lease
->t2
< client
->lease
->t1
)
697 if (client
->lease
->lifetime
< client
->lease
->t2
)
700 next_timeout
= client_compute_timeout(client
->request_sent
,
702 if (next_timeout
< usec
)
705 r
= sd_event_add_monotonic(client
->event
,
709 client_timeout_t2
, client
);
713 r
= sd_event_source_set_priority(client
->timeout_t2
,
714 client
->event_priority
);
718 next_timeout
= client_compute_timeout(client
->request_sent
,
719 client
->lease
->lifetime
);
720 if (next_timeout
< usec
)
723 r
= sd_event_add_monotonic(client
->event
,
724 &client
->timeout_expire
, next_timeout
,
726 client_timeout_expire
, client
);
730 r
= sd_event_source_set_priority(client
->timeout_expire
,
731 client
->event_priority
);
738 static int client_handle_message(sd_dhcp_client
*client
, DHCPMessage
*message
,
739 int len
, usec_t time_now
) {
740 int r
= 0, notify_event
= 0;
743 assert(client
->event
);
746 if (len
< DHCP_MESSAGE_SIZE
) {
747 log_dhcp_client(client
, "message too small (%d bytes): "
752 if (message
->op
!= BOOTREPLY
) {
753 log_dhcp_client(client
, "not a BOOTREPLY message: ignoring");
757 if (be32toh(message
->xid
) != client
->xid
) {
758 log_dhcp_client(client
, "received xid (%u) does not match "
759 "expected (%u): ignoring",
760 be32toh(message
->xid
), client
->xid
);
764 if (memcmp(&message
->chaddr
[0], &client
->mac_addr
.ether_addr_octet
,
766 log_dhcp_client(client
, "received chaddr does not match "
767 "expected: ignoring");
771 switch (client
->state
) {
772 case DHCP_STATE_SELECTING
:
774 r
= client_handle_offer(client
, message
, len
);
777 client
->timeout_resend
=
778 sd_event_source_unref(client
->timeout_resend
);
780 client
->state
= DHCP_STATE_REQUESTING
;
783 r
= sd_event_add_monotonic(client
->event
,
784 &client
->timeout_resend
,
786 client_timeout_resend
,
791 r
= sd_event_source_set_priority(client
->timeout_resend
,
792 client
->event_priority
);
799 case DHCP_STATE_REQUESTING
:
800 case DHCP_STATE_RENEWING
:
801 case DHCP_STATE_REBINDING
:
803 r
= client_handle_ack(client
, message
, len
);
805 if (r
== DHCP_EVENT_NO_LEASE
)
809 client
->timeout_resend
=
810 sd_event_source_unref(client
->timeout_resend
);
812 if (client
->state
== DHCP_STATE_REQUESTING
)
813 notify_event
= DHCP_EVENT_IP_ACQUIRE
;
814 else if (r
!= DHCP_EVENT_IP_ACQUIRE
)
817 client
->state
= DHCP_STATE_BOUND
;
820 client
->last_addr
= client
->lease
->address
;
822 r
= client_set_lease_timeouts(client
, time_now
);
827 client_notify(client
, notify_event
);
829 client
->receive_message
=
830 sd_event_source_unref(client
->receive_message
);
839 case DHCP_STATE_INIT
:
840 case DHCP_STATE_INIT_REBOOT
:
841 case DHCP_STATE_REBOOTING
:
842 case DHCP_STATE_BOUND
:
848 if (r
< 0 || r
== DHCP_EVENT_NO_LEASE
)
849 return client_stop(client
, r
);
854 static int client_receive_message_udp(sd_event_source
*s
, int fd
,
855 uint32_t revents
, void *userdata
) {
856 sd_dhcp_client
*client
= userdata
;
857 _cleanup_free_ DHCPMessage
*message
= NULL
;
858 int buflen
= 0, len
, r
;
863 assert(client
->event
);
865 r
= ioctl(fd
, FIONREAD
, &buflen
);
866 if (r
< 0 || buflen
<= 0)
867 buflen
= sizeof(DHCPMessage
) + DHCP_MIN_OPTIONS_SIZE
;
869 message
= malloc0(buflen
);
873 len
= read(fd
, message
, buflen
);
877 r
= sd_event_get_now_monotonic(client
->event
, &time_now
);
879 return client_stop(client
, r
);
881 return client_handle_message(client
, message
, len
,
885 static int client_receive_message_raw(sd_event_source
*s
, int fd
,
886 uint32_t revents
, void *userdata
) {
887 sd_dhcp_client
*client
= userdata
;
888 _cleanup_free_ DHCPPacket
*packet
= NULL
;
890 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct tpacket_auxdata
))];
891 struct iovec iov
= {};
892 struct msghdr msg
= {
895 .msg_control
= cmsgbuf
,
896 .msg_controllen
= sizeof(cmsgbuf
),
898 struct cmsghdr
*cmsg
;
899 bool checksum
= true;
900 int buflen
= 0, len
, r
;
904 assert(client
->event
);
906 r
= ioctl(fd
, FIONREAD
, &buflen
);
907 if (r
< 0 || buflen
<= 0)
908 buflen
= sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
;
910 packet
= malloc0(buflen
);
914 iov
.iov_base
= packet
;
915 iov
.iov_len
= buflen
;
917 len
= recvmsg(fd
, &msg
, 0);
919 log_dhcp_client(client
, "could not receive message from raw "
920 "socket: %s", strerror(errno
));
924 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
925 if (cmsg
->cmsg_level
== SOL_PACKET
&& cmsg
->cmsg_type
== PACKET_AUXDATA
) {
926 struct tpacket_auxdata
*aux
= (void *)CMSG_DATA(cmsg
);
928 checksum
= !(aux
->tp_status
& TP_STATUS_CSUMNOTREADY
);
933 r
= dhcp_packet_verify_headers(packet
, len
, checksum
);
937 len
-= DHCP_IP_UDP_SIZE
;
939 r
= sd_event_get_now_monotonic(client
->event
, &time_now
);
941 return client_stop(client
, r
);
943 return client_handle_message(client
, &packet
->dhcp
, len
, time_now
);
946 int sd_dhcp_client_start(sd_dhcp_client
*client
) {
949 assert_return(client
, -EINVAL
);
950 assert_return(client
->event
, -EINVAL
);
951 assert_return(client
->index
> 0, -EINVAL
);
952 assert_return(client
->state
== DHCP_STATE_INIT
||
953 client
->state
== DHCP_STATE_INIT_REBOOT
, -EBUSY
);
955 client
->xid
= random_u32();
957 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
);
960 client_stop(client
, r
);
965 client
->start_time
= now(CLOCK_MONOTONIC
);
968 log_dhcp_client(client
, "STARTED");
970 return client_initialize_events(client
, client_receive_message_raw
,
974 int sd_dhcp_client_stop(sd_dhcp_client
*client
) {
975 return client_stop(client
, DHCP_EVENT_STOP
);
978 int sd_dhcp_client_attach_event(sd_dhcp_client
*client
, sd_event
*event
,
982 assert_return(client
, -EINVAL
);
983 assert_return(!client
->event
, -EBUSY
);
986 client
->event
= sd_event_ref(event
);
988 r
= sd_event_default(&client
->event
);
993 client
->event_priority
= priority
;
998 int sd_dhcp_client_detach_event(sd_dhcp_client
*client
) {
999 assert_return(client
, -EINVAL
);
1001 client
->event
= sd_event_unref(client
->event
);
1006 sd_event
*sd_dhcp_client_get_event(sd_dhcp_client
*client
) {
1010 return client
->event
;
1013 void sd_dhcp_client_free(sd_dhcp_client
*client
) {
1017 sd_dhcp_client_stop(client
);
1018 sd_dhcp_client_detach_event(client
);
1020 free(client
->req_opts
);
1024 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client
*, sd_dhcp_client_free
);
1025 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_freep)
1027 int sd_dhcp_client_new(sd_dhcp_client
**ret
) {
1028 _cleanup_dhcp_client_free_ sd_dhcp_client
*client
= NULL
;
1030 assert_return(ret
, -EINVAL
);
1032 client
= new0(sd_dhcp_client
, 1);
1036 client
->state
= DHCP_STATE_INIT
;
1039 client
->attempt
= 1;
1041 client
->req_opts_size
= ELEMENTSOF(default_req_opts
);
1043 client
->req_opts
= memdup(default_req_opts
, client
->req_opts_size
);
1044 if (!client
->req_opts
)