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 <net/if_arp.h>
26 #include <sys/param.h>
27 #include <sys/ioctl.h>
33 #include "dhcp-protocol.h"
34 #include "dhcp-internal.h"
35 #include "dhcp-lease-internal.h"
36 #include "sd-dhcp-client.h"
38 struct sd_dhcp_client
{
44 sd_event_source
*timeout_resend
;
47 union sockaddr_union link
;
48 sd_event_source
*receive_message
;
50 size_t req_opts_allocated
;
55 struct ether_addr mac_addr
;
62 sd_event_source
*timeout_t1
;
63 sd_event_source
*timeout_t2
;
64 sd_event_source
*timeout_expire
;
65 sd_dhcp_client_cb_t cb
;
70 static const uint8_t default_req_opts
[] = {
71 DHCP_OPTION_SUBNET_MASK
,
73 DHCP_OPTION_HOST_NAME
,
74 DHCP_OPTION_DOMAIN_NAME
,
75 DHCP_OPTION_DOMAIN_NAME_SERVER
,
76 DHCP_OPTION_NTP_SERVER
,
79 static int client_receive_message_raw(sd_event_source
*s
, int fd
,
80 uint32_t revents
, void *userdata
);
81 static int client_receive_message_udp(sd_event_source
*s
, int fd
,
82 uint32_t revents
, void *userdata
);
83 static sd_dhcp_client
*client_stop(sd_dhcp_client
*client
, int error
);
85 int sd_dhcp_client_set_callback(sd_dhcp_client
*client
, sd_dhcp_client_cb_t cb
,
87 assert_return(client
, -EINVAL
);
90 client
->userdata
= userdata
;
95 int sd_dhcp_client_set_request_option(sd_dhcp_client
*client
, uint8_t option
) {
98 assert_return(client
, -EINVAL
);
99 assert_return (client
->state
== DHCP_STATE_INIT
, -EBUSY
);
102 case DHCP_OPTION_PAD
:
103 case DHCP_OPTION_OVERLOAD
:
104 case DHCP_OPTION_MESSAGE_TYPE
:
105 case DHCP_OPTION_PARAMETER_REQUEST_LIST
:
106 case DHCP_OPTION_END
:
113 for (i
= 0; i
< client
->req_opts_size
; i
++)
114 if (client
->req_opts
[i
] == option
)
117 if (!GREEDY_REALLOC(client
->req_opts
, client
->req_opts_allocated
,
118 client
->req_opts_size
+ 1))
121 client
->req_opts
[client
->req_opts_size
++] = option
;
126 int sd_dhcp_client_set_request_address(sd_dhcp_client
*client
,
127 const struct in_addr
*last_addr
) {
128 assert_return(client
, -EINVAL
);
129 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
132 client
->last_addr
= last_addr
->s_addr
;
134 client
->last_addr
= INADDR_ANY
;
139 int sd_dhcp_client_set_index(sd_dhcp_client
*client
, int interface_index
) {
140 assert_return(client
, -EINVAL
);
141 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
142 assert_return(interface_index
>= -1, -EINVAL
);
144 client
->index
= interface_index
;
149 int sd_dhcp_client_set_mac(sd_dhcp_client
*client
,
150 const struct ether_addr
*addr
) {
151 bool need_restart
= false;
153 assert_return(client
, -EINVAL
);
154 assert_return(addr
, -EINVAL
);
156 if (memcmp(&client
->client_id
.mac_addr
, addr
, ETH_ALEN
) == 0)
159 if (client
->state
!= DHCP_STATE_INIT
) {
160 log_dhcp_client(client
, "Changing MAC address on running DHCP "
161 "client, restarting");
163 client
= client_stop(client
, DHCP_EVENT_STOP
);
169 memcpy(&client
->client_id
.mac_addr
, addr
, ETH_ALEN
);
170 client
->client_id
.type
= 0x01;
173 sd_dhcp_client_start(client
);
178 int sd_dhcp_client_get_lease(sd_dhcp_client
*client
, sd_dhcp_lease
**ret
) {
179 assert_return(client
, -EINVAL
);
180 assert_return(ret
, -EINVAL
);
182 if (client
->state
!= DHCP_STATE_BOUND
&&
183 client
->state
!= DHCP_STATE_RENEWING
&&
184 client
->state
!= DHCP_STATE_REBINDING
)
185 return -EADDRNOTAVAIL
;
187 *ret
= sd_dhcp_lease_ref(client
->lease
);
192 static sd_dhcp_client
*client_notify(sd_dhcp_client
*client
, int event
) {
194 client
= sd_dhcp_client_ref(client
);
195 client
->cb(client
, event
, client
->userdata
);
196 client
= sd_dhcp_client_unref(client
);
202 static int client_initialize(sd_dhcp_client
*client
) {
203 assert_return(client
, -EINVAL
);
205 client
->receive_message
=
206 sd_event_source_unref(client
->receive_message
);
208 client
->fd
= safe_close(client
->fd
);
210 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
212 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
213 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
214 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
218 client
->state
= DHCP_STATE_INIT
;
222 client
->lease
= sd_dhcp_lease_unref(client
->lease
);
227 static sd_dhcp_client
*client_stop(sd_dhcp_client
*client
, int error
) {
228 assert_return(client
, NULL
);
230 log_dhcp_client(client
, "STOPPED %d", error
);
232 client
= client_notify(client
, error
);
235 client_initialize(client
);
240 static int client_message_init(sd_dhcp_client
*client
, DHCPMessage
*message
,
241 uint8_t type
, uint8_t **opt
, size_t *optlen
) {
245 assert(client
->secs
);
250 r
= dhcp_message_init(message
, BOOTREQUEST
, client
->xid
, type
, opt
,
255 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
256 refuse to issue an DHCP lease if 'secs' is set to zero */
257 message
->secs
= htobe16(client
->secs
);
259 memcpy(&message
->chaddr
, &client
->client_id
.mac_addr
, ETH_ALEN
);
261 if (client
->state
== DHCP_STATE_RENEWING
||
262 client
->state
== DHCP_STATE_REBINDING
)
263 message
->ciaddr
= client
->lease
->address
;
265 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
266 Identifier option is not set */
267 r
= dhcp_option_append(opt
, optlen
, DHCP_OPTION_CLIENT_IDENTIFIER
,
268 sizeof(client
->client_id
), &client
->client_id
);
272 if (type
== DHCP_DISCOVER
|| type
== DHCP_REQUEST
) {
275 r
= dhcp_option_append(opt
, optlen
,
276 DHCP_OPTION_PARAMETER_REQUEST_LIST
,
277 client
->req_opts_size
,
282 /* Some DHCP servers will send bigger DHCP packets than the
283 defined default size unless the Maximum Messge Size option
284 is explicitely set */
285 max_size
= htobe16(DHCP_IP_UDP_SIZE
+ DHCP_MESSAGE_SIZE
+
286 DHCP_MIN_OPTIONS_SIZE
);
287 r
= dhcp_option_append(opt
, optlen
,
288 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
,
297 static int dhcp_client_send_raw(sd_dhcp_client
*client
, DHCPPacket
*packet
,
299 dhcp_packet_append_ip_headers(packet
, INADDR_ANY
, DHCP_PORT_CLIENT
,
300 INADDR_BROADCAST
, DHCP_PORT_SERVER
, len
);
302 return dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
306 static int client_send_discover(sd_dhcp_client
*client
) {
307 _cleanup_free_ DHCPPacket
*discover
= NULL
;
315 r
= sd_event_now(client
->event
, CLOCK_MONOTONIC
, &time_now
);
318 assert(time_now
>= client
->start_time
);
320 /* seconds between sending first and last DISCOVER
321 * must always be strictly positive to deal with broken servers */
322 client
->secs
= ((time_now
- client
->start_time
) / USEC_PER_SEC
) ? : 1;
324 optlen
= DHCP_MIN_OPTIONS_SIZE
;
325 len
= sizeof(DHCPPacket
) + optlen
;
327 discover
= malloc0(len
);
331 r
= client_message_init(client
, &discover
->dhcp
, DHCP_DISCOVER
,
336 if (client
->last_addr
!= INADDR_ANY
) {
337 r
= dhcp_option_append(&opt
, &optlen
,
338 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
339 4, &client
->last_addr
);
344 r
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
348 r
= dhcp_client_send_raw(client
, discover
, len
- optlen
);
352 log_dhcp_client(client
, "DISCOVER");
357 static int client_send_request(sd_dhcp_client
*client
) {
358 _cleanup_free_ DHCPPacket
*request
;
363 optlen
= DHCP_MIN_OPTIONS_SIZE
;
364 len
= sizeof(DHCPPacket
) + optlen
;
366 request
= malloc0(len
);
370 r
= client_message_init(client
, &request
->dhcp
, DHCP_REQUEST
, &opt
,
375 switch (client
->state
) {
377 case DHCP_STATE_INIT_REBOOT
:
378 r
= dhcp_option_append(&opt
, &optlen
,
379 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
380 4, &client
->last_addr
);
385 case DHCP_STATE_REQUESTING
:
386 r
= dhcp_option_append(&opt
, &optlen
,
387 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
388 4, &client
->lease
->address
);
392 r
= dhcp_option_append(&opt
, &optlen
,
393 DHCP_OPTION_SERVER_IDENTIFIER
,
394 4, &client
->lease
->server_address
);
399 case DHCP_STATE_INIT
:
400 case DHCP_STATE_SELECTING
:
401 case DHCP_STATE_REBOOTING
:
402 case DHCP_STATE_BOUND
:
403 case DHCP_STATE_RENEWING
:
404 case DHCP_STATE_REBINDING
:
409 r
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
413 if (client
->state
== DHCP_STATE_RENEWING
) {
414 r
= dhcp_network_send_udp_socket(client
->fd
,
415 client
->lease
->server_address
,
418 len
- optlen
- DHCP_IP_UDP_SIZE
);
420 r
= dhcp_client_send_raw(client
, request
, len
- optlen
);
425 log_dhcp_client(client
, "REQUEST");
430 static int client_timeout_resend(sd_event_source
*s
, uint64_t usec
,
432 sd_dhcp_client
*client
= userdata
;
433 usec_t next_timeout
= 0;
440 assert(client
->event
);
442 r
= sd_event_now(client
->event
, CLOCK_MONOTONIC
, &time_now
);
446 switch (client
->state
) {
447 case DHCP_STATE_RENEWING
:
449 time_left
= (client
->lease
->t2
- client
->lease
->t1
) / 2;
453 next_timeout
= time_now
+ time_left
* USEC_PER_SEC
;
457 case DHCP_STATE_REBINDING
:
459 time_left
= (client
->lease
->lifetime
- client
->lease
->t2
) / 2;
463 next_timeout
= time_now
+ time_left
* USEC_PER_SEC
;
466 case DHCP_STATE_REBOOTING
:
467 /* start over as we did not receive a timely ack or nak */
468 client
->state
= DHCP_STATE_INIT
;
470 client
->xid
= random_u32();
473 case DHCP_STATE_INIT
:
474 case DHCP_STATE_INIT_REBOOT
:
475 case DHCP_STATE_SELECTING
:
476 case DHCP_STATE_REQUESTING
:
477 case DHCP_STATE_BOUND
:
479 if (client
->attempt
< 64)
480 client
->attempt
*= 2;
482 next_timeout
= time_now
+ (client
->attempt
- 1) * USEC_PER_SEC
;
487 next_timeout
+= (random_u32() & 0x1fffff);
489 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
491 r
= sd_event_add_time(client
->event
,
492 &client
->timeout_resend
,
494 next_timeout
, 10 * USEC_PER_MSEC
,
495 client_timeout_resend
, client
);
499 r
= sd_event_source_set_priority(client
->timeout_resend
,
500 client
->event_priority
);
504 switch (client
->state
) {
505 case DHCP_STATE_INIT
:
506 r
= client_send_discover(client
);
508 client
->state
= DHCP_STATE_SELECTING
;
511 if (client
->attempt
>= 64)
517 case DHCP_STATE_SELECTING
:
518 r
= client_send_discover(client
);
519 if (r
< 0 && client
->attempt
>= 64)
524 case DHCP_STATE_INIT_REBOOT
:
525 case DHCP_STATE_REQUESTING
:
526 case DHCP_STATE_RENEWING
:
527 case DHCP_STATE_REBINDING
:
528 r
= client_send_request(client
);
529 if (r
< 0 && client
->attempt
>= 64)
532 if (client
->state
== DHCP_STATE_INIT_REBOOT
)
533 client
->state
= DHCP_STATE_REBOOTING
;
535 client
->request_sent
= time_now
;
539 case DHCP_STATE_REBOOTING
:
540 case DHCP_STATE_BOUND
:
548 client_stop(client
, r
);
550 /* Errors were dealt with when stopping the client, don't spill
551 errors into the event loop handler */
555 static int client_initialize_events(sd_dhcp_client
*client
,
556 sd_event_io_handler_t io_callback
) {
560 assert(client
->event
);
562 r
= sd_event_add_io(client
->event
, &client
->receive_message
,
563 client
->fd
, EPOLLIN
, io_callback
,
568 r
= sd_event_source_set_priority(client
->receive_message
,
569 client
->event_priority
);
573 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
575 r
= sd_event_add_time(client
->event
,
576 &client
->timeout_resend
,
579 client_timeout_resend
, client
);
583 r
= sd_event_source_set_priority(client
->timeout_resend
,
584 client
->event_priority
);
588 client_stop(client
, r
);
594 static int client_start(sd_dhcp_client
*client
) {
597 assert_return(client
, -EINVAL
);
598 assert_return(client
->event
, -EINVAL
);
599 assert_return(client
->index
> 0, -EINVAL
);
600 assert_return(client
->fd
< 0, -EBUSY
);
601 assert_return(client
->xid
== 0, -EINVAL
);
602 assert_return(client
->state
== DHCP_STATE_INIT
||
603 client
->state
== DHCP_STATE_INIT_REBOOT
, -EBUSY
);
605 client
->xid
= random_u32();
607 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
, client
->xid
);
610 client_stop(client
, r
);
615 if (client
->state
== DHCP_STATE_INIT
) {
616 client
->start_time
= now(CLOCK_MONOTONIC
);
620 log_dhcp_client(client
, "STARTED");
622 return client_initialize_events(client
, client_receive_message_raw
);
625 static int client_timeout_expire(sd_event_source
*s
, uint64_t usec
,
627 sd_dhcp_client
*client
= userdata
;
629 log_dhcp_client(client
, "EXPIRED");
631 client
= client_notify(client
, DHCP_EVENT_EXPIRED
);
633 /* lease was lost, start over if not freed */
635 client_initialize(client
);
636 client_start(client
);
642 static int client_timeout_t2(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
643 sd_dhcp_client
*client
= userdata
;
646 client
->receive_message
= sd_event_source_unref(client
->receive_message
);
647 client
->fd
= safe_close(client
->fd
);
649 client
->state
= DHCP_STATE_REBINDING
;
652 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
, client
->xid
);
654 client_stop(client
, r
);
660 log_dhcp_client(client
, "TIMEOUT T2");
662 return client_initialize_events(client
, client_receive_message_raw
);
665 static int client_timeout_t1(sd_event_source
*s
, uint64_t usec
,
667 sd_dhcp_client
*client
= userdata
;
670 client
->state
= DHCP_STATE_RENEWING
;
673 r
= dhcp_network_bind_udp_socket(client
->index
,
674 client
->lease
->address
,
677 client_stop(client
, r
);
683 log_dhcp_client(client
, "TIMEOUT T1");
685 return client_initialize_events(client
, client_receive_message_udp
);
688 static int client_handle_offer(sd_dhcp_client
*client
, DHCPMessage
*offer
,
690 _cleanup_dhcp_lease_unref_ sd_dhcp_lease
*lease
= NULL
;
693 r
= dhcp_lease_new(&lease
);
697 r
= dhcp_option_parse(offer
, len
, dhcp_lease_parse_options
, lease
);
698 if (r
!= DHCP_OFFER
) {
699 log_dhcp_client(client
, "receieved message was not an OFFER, ignoring");
703 lease
->next_server
= offer
->siaddr
;
705 lease
->address
= offer
->yiaddr
;
707 if (lease
->address
== INADDR_ANY
||
708 lease
->server_address
== INADDR_ANY
||
709 lease
->lifetime
== 0) {
710 log_dhcp_client(client
, "receieved lease lacks address, server "
711 "address or lease lifetime, ignoring");
715 if (lease
->subnet_mask
== INADDR_ANY
) {
716 r
= dhcp_lease_set_default_subnet_mask(lease
);
718 log_dhcp_client(client
, "receieved lease lacks subnet "
719 "mask, and a fallback one can not be "
720 "generated, ignoring");
725 client
->lease
= lease
;
728 log_dhcp_client(client
, "OFFER");
733 static int client_handle_ack(sd_dhcp_client
*client
, DHCPMessage
*ack
,
735 _cleanup_dhcp_lease_unref_ sd_dhcp_lease
*lease
= NULL
;
738 r
= dhcp_lease_new(&lease
);
742 r
= dhcp_option_parse(ack
, len
, dhcp_lease_parse_options
, lease
);
744 log_dhcp_client(client
, "NAK");
745 return DHCP_EVENT_NO_LEASE
;
749 log_dhcp_client(client
, "receieved message was not an ACK, ignoring");
753 lease
->next_server
= ack
->siaddr
;
755 lease
->address
= ack
->yiaddr
;
757 if (lease
->address
== INADDR_ANY
||
758 lease
->server_address
== INADDR_ANY
||
759 lease
->lifetime
== 0) {
760 log_dhcp_client(client
, "receieved lease lacks address, server "
761 "address or lease lifetime, ignoring");
765 if (lease
->subnet_mask
== INADDR_ANY
) {
766 r
= dhcp_lease_set_default_subnet_mask(lease
);
768 log_dhcp_client(client
, "receieved lease lacks subnet "
769 "mask, and a fallback one can not be "
770 "generated, ignoring");
775 r
= DHCP_EVENT_IP_ACQUIRE
;
777 if (client
->lease
->address
!= lease
->address
||
778 client
->lease
->subnet_mask
!= lease
->subnet_mask
||
779 client
->lease
->router
!= lease
->router
) {
780 r
= DHCP_EVENT_IP_CHANGE
;
783 client
->lease
= sd_dhcp_lease_unref(client
->lease
);
786 client
->lease
= lease
;
789 log_dhcp_client(client
, "ACK");
794 static uint64_t client_compute_timeout(sd_dhcp_client
*client
,
795 uint32_t lifetime
, double factor
) {
797 assert(client
->request_sent
);
800 return client
->request_sent
+ ((lifetime
- 3) * USEC_PER_SEC
* factor
) +
801 + (random_u32() & 0x1fffff);
804 static int client_set_lease_timeouts(sd_dhcp_client
*client
) {
806 uint64_t lifetime_timeout
;
809 char time_string
[FORMAT_TIMESPAN_MAX
];
813 assert(client
->event
);
814 assert(client
->lease
);
815 assert(client
->lease
->lifetime
);
817 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
818 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
819 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
821 /* don't set timers for infinite leases */
822 if (client
->lease
->lifetime
== 0xffffffff)
825 r
= sd_event_now(client
->event
, CLOCK_MONOTONIC
, &time_now
);
828 assert(client
->request_sent
<= time_now
);
830 /* convert the various timeouts from relative (secs) to absolute (usecs) */
831 lifetime_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 1);
832 if (client
->lease
->t1
&& client
->lease
->t2
) {
833 /* both T1 and T2 are given */
834 if (client
->lease
->t1
< client
->lease
->t2
&&
835 client
->lease
->t2
< client
->lease
->lifetime
) {
836 /* they are both valid */
837 t2_timeout
= client_compute_timeout(client
, client
->lease
->t2
, 1);
838 t1_timeout
= client_compute_timeout(client
, client
->lease
->t1
, 1);
841 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
842 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
843 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
844 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
846 } else if (client
->lease
->t2
&& client
->lease
->t2
< client
->lease
->lifetime
) {
847 /* only T2 is given, and it is valid */
848 t2_timeout
= client_compute_timeout(client
, client
->lease
->t2
, 1);
849 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
850 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
851 if (t2_timeout
<= t1_timeout
) {
852 /* the computed T1 would be invalid, so discard T2 */
853 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
854 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
856 } else if (client
->lease
->t1
&& client
->lease
->t1
< client
->lease
->lifetime
) {
857 /* only T1 is given, and it is valid */
858 t1_timeout
= client_compute_timeout(client
, client
->lease
->t1
, 1);
859 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
860 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
861 if (t2_timeout
<= t1_timeout
) {
862 /* the computed T2 would be invalid, so discard T1 */
863 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
864 client
->lease
->t2
= client
->lease
->lifetime
/ 2;
867 /* fall back to the default timeouts */
868 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
869 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
870 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
871 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
874 /* arm lifetime timeout */
875 r
= sd_event_add_time(client
->event
, &client
->timeout_expire
,
877 lifetime_timeout
, 10 * USEC_PER_MSEC
,
878 client_timeout_expire
, client
);
882 r
= sd_event_source_set_priority(client
->timeout_expire
,
883 client
->event_priority
);
887 log_dhcp_client(client
, "lease expires in %s",
888 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
,
889 lifetime_timeout
- time_now
, 0));
891 /* don't arm earlier timeouts if this has already expired */
892 if (lifetime_timeout
<= time_now
)
896 r
= sd_event_add_time(client
->event
,
901 client_timeout_t2
, client
);
905 r
= sd_event_source_set_priority(client
->timeout_t2
,
906 client
->event_priority
);
910 log_dhcp_client(client
, "T2 expires in %s",
911 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
,
912 t2_timeout
- time_now
, 0));
914 /* don't arm earlier timeout if this has already expired */
915 if (t2_timeout
<= time_now
)
919 r
= sd_event_add_time(client
->event
,
922 t1_timeout
, 10 * USEC_PER_MSEC
,
923 client_timeout_t1
, client
);
927 r
= sd_event_source_set_priority(client
->timeout_t1
,
928 client
->event_priority
);
932 log_dhcp_client(client
, "T1 expires in %s",
933 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
,
934 t1_timeout
- time_now
, 0));
939 static int client_handle_message(sd_dhcp_client
*client
, DHCPMessage
*message
,
941 int r
= 0, notify_event
= 0;
944 assert(client
->event
);
947 if (be32toh(message
->magic
) != DHCP_MAGIC_COOKIE
) {
948 log_dhcp_client(client
, "not a DHCP message: ignoring");
952 if (message
->op
!= BOOTREPLY
) {
953 log_dhcp_client(client
, "not a BOOTREPLY message: ignoring");
957 if (be32toh(message
->xid
) != client
->xid
) {
958 log_dhcp_client(client
, "received xid (%u) does not match "
959 "expected (%u): ignoring",
960 be32toh(message
->xid
), client
->xid
);
964 if (message
->htype
!= ARPHRD_ETHER
|| message
->hlen
!= ETHER_ADDR_LEN
) {
965 log_dhcp_client(client
, "not an ethernet packet");
969 if (memcmp(&message
->chaddr
[0], &client
->client_id
.mac_addr
,
971 log_dhcp_client(client
, "received chaddr does not match "
972 "expected: ignoring");
976 switch (client
->state
) {
977 case DHCP_STATE_SELECTING
:
979 r
= client_handle_offer(client
, message
, len
);
982 client
->timeout_resend
=
983 sd_event_source_unref(client
->timeout_resend
);
985 client
->state
= DHCP_STATE_REQUESTING
;
988 r
= sd_event_add_time(client
->event
,
989 &client
->timeout_resend
,
992 client_timeout_resend
, client
);
996 r
= sd_event_source_set_priority(client
->timeout_resend
,
997 client
->event_priority
);
1000 } else if (r
== -ENOMSG
)
1001 /* invalid message, let's ignore it */
1006 case DHCP_STATE_REBOOTING
:
1007 case DHCP_STATE_REQUESTING
:
1008 case DHCP_STATE_RENEWING
:
1009 case DHCP_STATE_REBINDING
:
1011 r
= client_handle_ack(client
, message
, len
);
1012 if (r
== DHCP_EVENT_NO_LEASE
) {
1014 client
->timeout_resend
=
1015 sd_event_source_unref(client
->timeout_resend
);
1017 if (client
->state
== DHCP_STATE_REBOOTING
) {
1018 r
= client_initialize(client
);
1022 r
= client_start(client
);
1028 } else if (r
>= 0) {
1029 client
->timeout_resend
=
1030 sd_event_source_unref(client
->timeout_resend
);
1032 if (IN_SET(client
->state
, DHCP_STATE_REQUESTING
,
1033 DHCP_STATE_REBOOTING
))
1034 notify_event
= DHCP_EVENT_IP_ACQUIRE
;
1035 else if (r
!= DHCP_EVENT_IP_ACQUIRE
)
1038 client
->state
= DHCP_STATE_BOUND
;
1039 client
->attempt
= 1;
1041 client
->last_addr
= client
->lease
->address
;
1043 r
= client_set_lease_timeouts(client
);
1048 client
= client_notify(client
, notify_event
);
1053 client
->receive_message
=
1054 sd_event_source_unref(client
->receive_message
);
1055 client
->fd
= safe_close(client
->fd
);
1056 } else if (r
== -ENOMSG
)
1057 /* invalid message, let's ignore it */
1062 case DHCP_STATE_INIT
:
1063 case DHCP_STATE_INIT_REBOOT
:
1064 case DHCP_STATE_BOUND
:
1070 if (r
< 0 || r
== DHCP_EVENT_NO_LEASE
)
1071 client_stop(client
, r
);
1076 static int client_receive_message_udp(sd_event_source
*s
, int fd
,
1077 uint32_t revents
, void *userdata
) {
1078 sd_dhcp_client
*client
= userdata
;
1079 _cleanup_free_ DHCPMessage
*message
= NULL
;
1080 int buflen
= 0, len
, r
;
1085 r
= ioctl(fd
, FIONREAD
, &buflen
);
1086 if (r
< 0 || buflen
<= 0)
1087 buflen
= sizeof(DHCPMessage
) + DHCP_MIN_OPTIONS_SIZE
;
1089 message
= malloc0(buflen
);
1093 len
= read(fd
, message
, buflen
);
1095 log_dhcp_client(client
, "could not receive message from UDP "
1096 "socket: %s", strerror(errno
));
1098 } else if ((size_t)len
< sizeof(DHCPMessage
))
1101 return client_handle_message(client
, message
, len
);
1104 static int client_receive_message_raw(sd_event_source
*s
, int fd
,
1105 uint32_t revents
, void *userdata
) {
1106 sd_dhcp_client
*client
= userdata
;
1107 _cleanup_free_ DHCPPacket
*packet
= NULL
;
1108 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct tpacket_auxdata
))];
1109 struct iovec iov
= {};
1110 struct msghdr msg
= {
1113 .msg_control
= cmsgbuf
,
1114 .msg_controllen
= sizeof(cmsgbuf
),
1116 struct cmsghdr
*cmsg
;
1117 bool checksum
= true;
1118 int buflen
= 0, len
, r
;
1123 r
= ioctl(fd
, FIONREAD
, &buflen
);
1124 if (r
< 0 || buflen
<= 0)
1125 buflen
= sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
;
1127 packet
= malloc0(buflen
);
1131 iov
.iov_base
= packet
;
1132 iov
.iov_len
= buflen
;
1134 len
= recvmsg(fd
, &msg
, 0);
1136 log_dhcp_client(client
, "could not receive message from raw "
1137 "socket: %s", strerror(errno
));
1139 } else if ((size_t)len
< sizeof(DHCPPacket
))
1142 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
1143 if (cmsg
->cmsg_level
== SOL_PACKET
&&
1144 cmsg
->cmsg_type
== PACKET_AUXDATA
&&
1145 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct tpacket_auxdata
))) {
1146 struct tpacket_auxdata
*aux
= (struct tpacket_auxdata
*)CMSG_DATA(cmsg
);
1148 checksum
= !(aux
->tp_status
& TP_STATUS_CSUMNOTREADY
);
1153 r
= dhcp_packet_verify_headers(packet
, len
, checksum
);
1157 len
-= DHCP_IP_UDP_SIZE
;
1159 return client_handle_message(client
, &packet
->dhcp
, len
);
1162 int sd_dhcp_client_start(sd_dhcp_client
*client
) {
1165 assert_return(client
, -EINVAL
);
1167 r
= client_initialize(client
);
1171 if (client
->last_addr
)
1172 client
->state
= DHCP_STATE_INIT_REBOOT
;
1174 return client_start(client
);
1177 int sd_dhcp_client_stop(sd_dhcp_client
*client
) {
1178 assert_return(client
, -EINVAL
);
1180 client_stop(client
, DHCP_EVENT_STOP
);
1185 int sd_dhcp_client_attach_event(sd_dhcp_client
*client
, sd_event
*event
,
1189 assert_return(client
, -EINVAL
);
1190 assert_return(!client
->event
, -EBUSY
);
1193 client
->event
= sd_event_ref(event
);
1195 r
= sd_event_default(&client
->event
);
1200 client
->event_priority
= priority
;
1205 int sd_dhcp_client_detach_event(sd_dhcp_client
*client
) {
1206 assert_return(client
, -EINVAL
);
1208 client
->event
= sd_event_unref(client
->event
);
1213 sd_event
*sd_dhcp_client_get_event(sd_dhcp_client
*client
) {
1217 return client
->event
;
1220 sd_dhcp_client
*sd_dhcp_client_ref(sd_dhcp_client
*client
) {
1222 assert_se(REFCNT_INC(client
->n_ref
) >= 2);
1227 sd_dhcp_client
*sd_dhcp_client_unref(sd_dhcp_client
*client
) {
1228 if (client
&& REFCNT_DEC(client
->n_ref
) <= 0) {
1229 log_dhcp_client(client
, "UNREF");
1231 client_initialize(client
);
1233 client
->receive_message
=
1234 sd_event_source_unref(client
->receive_message
);
1236 sd_dhcp_client_detach_event(client
);
1238 free(client
->req_opts
);
1247 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client
*, sd_dhcp_client_unref
);
1248 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1250 int sd_dhcp_client_new(sd_dhcp_client
**ret
) {
1251 _cleanup_dhcp_client_free_ sd_dhcp_client
*client
= NULL
;
1253 assert_return(ret
, -EINVAL
);
1255 client
= new0(sd_dhcp_client
, 1);
1259 client
->n_ref
= REFCNT_INIT
;
1260 client
->state
= DHCP_STATE_INIT
;
1263 client
->attempt
= 1;
1265 client
->req_opts_size
= ELEMENTSOF(default_req_opts
);
1267 client
->req_opts
= memdup(default_req_opts
, client
->req_opts_size
);
1268 if (!client
->req_opts
)