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 <netinet/ether.h>
27 #include <sys/param.h>
28 #include <sys/ioctl.h>
35 #include "dhcp-protocol.h"
36 #include "dhcp-internal.h"
37 #include "dhcp-lease-internal.h"
38 #include "sd-dhcp-client.h"
40 struct sd_dhcp_client
{
46 sd_event_source
*timeout_resend
;
49 union sockaddr_union link
;
50 sd_event_source
*receive_message
;
52 size_t req_opts_allocated
;
57 struct ether_addr mac_addr
;
64 sd_event_source
*timeout_t1
;
65 sd_event_source
*timeout_t2
;
66 sd_event_source
*timeout_expire
;
67 sd_dhcp_client_cb_t cb
;
72 static const uint8_t default_req_opts
[] = {
73 DHCP_OPTION_SUBNET_MASK
,
75 DHCP_OPTION_HOST_NAME
,
76 DHCP_OPTION_DOMAIN_NAME
,
77 DHCP_OPTION_DOMAIN_NAME_SERVER
,
78 DHCP_OPTION_NTP_SERVER
,
81 static int client_receive_message_raw(sd_event_source
*s
, int fd
,
82 uint32_t revents
, void *userdata
);
83 static int client_receive_message_udp(sd_event_source
*s
, int fd
,
84 uint32_t revents
, void *userdata
);
85 static void client_stop(sd_dhcp_client
*client
, int error
);
87 int sd_dhcp_client_set_callback(sd_dhcp_client
*client
, sd_dhcp_client_cb_t cb
,
89 assert_return(client
, -EINVAL
);
92 client
->userdata
= userdata
;
97 int sd_dhcp_client_set_request_option(sd_dhcp_client
*client
, uint8_t option
) {
100 assert_return(client
, -EINVAL
);
101 assert_return (IN_SET(client
->state
, DHCP_STATE_INIT
,
102 DHCP_STATE_STOPPED
), -EBUSY
);
105 case DHCP_OPTION_PAD
:
106 case DHCP_OPTION_OVERLOAD
:
107 case DHCP_OPTION_MESSAGE_TYPE
:
108 case DHCP_OPTION_PARAMETER_REQUEST_LIST
:
109 case DHCP_OPTION_END
:
116 for (i
= 0; i
< client
->req_opts_size
; i
++)
117 if (client
->req_opts
[i
] == option
)
120 if (!GREEDY_REALLOC(client
->req_opts
, client
->req_opts_allocated
,
121 client
->req_opts_size
+ 1))
124 client
->req_opts
[client
->req_opts_size
++] = option
;
129 int sd_dhcp_client_set_request_address(sd_dhcp_client
*client
,
130 const struct in_addr
*last_addr
) {
131 assert_return(client
, -EINVAL
);
132 assert_return (IN_SET(client
->state
, DHCP_STATE_INIT
,
133 DHCP_STATE_STOPPED
), -EBUSY
);
136 client
->last_addr
= last_addr
->s_addr
;
138 client
->last_addr
= INADDR_ANY
;
143 int sd_dhcp_client_set_index(sd_dhcp_client
*client
, int interface_index
) {
144 assert_return(client
, -EINVAL
);
145 assert_return (IN_SET(client
->state
, DHCP_STATE_INIT
,
146 DHCP_STATE_STOPPED
), -EBUSY
);
147 assert_return(interface_index
> 0, -EINVAL
);
149 client
->index
= interface_index
;
154 int sd_dhcp_client_set_mac(sd_dhcp_client
*client
,
155 const struct ether_addr
*addr
) {
156 DHCP_CLIENT_DONT_DESTROY(client
);
157 bool need_restart
= false;
159 assert_return(client
, -EINVAL
);
160 assert_return(addr
, -EINVAL
);
162 if (memcmp(&client
->client_id
.mac_addr
, addr
, ETH_ALEN
) == 0)
165 if (!IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
)) {
166 log_dhcp_client(client
, "Changing MAC address on running DHCP "
167 "client, restarting");
169 client_stop(client
, DHCP_EVENT_STOP
);
172 memcpy(&client
->client_id
.mac_addr
, addr
, ETH_ALEN
);
173 client
->client_id
.type
= 0x01;
175 if (need_restart
&& client
->state
!= DHCP_STATE_STOPPED
)
176 sd_dhcp_client_start(client
);
181 int sd_dhcp_client_get_lease(sd_dhcp_client
*client
, sd_dhcp_lease
**ret
) {
182 assert_return(client
, -EINVAL
);
183 assert_return(ret
, -EINVAL
);
185 if (client
->state
!= DHCP_STATE_BOUND
&&
186 client
->state
!= DHCP_STATE_RENEWING
&&
187 client
->state
!= DHCP_STATE_REBINDING
)
188 return -EADDRNOTAVAIL
;
190 *ret
= sd_dhcp_lease_ref(client
->lease
);
195 static void client_notify(sd_dhcp_client
*client
, int event
) {
197 client
->cb(client
, event
, client
->userdata
);
200 static int client_initialize(sd_dhcp_client
*client
) {
201 assert_return(client
, -EINVAL
);
203 client
->receive_message
=
204 sd_event_source_unref(client
->receive_message
);
206 client
->fd
= asynchronous_close(client
->fd
);
208 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
210 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
211 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
212 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
216 client
->state
= DHCP_STATE_INIT
;
220 client
->lease
= sd_dhcp_lease_unref(client
->lease
);
225 static void client_stop(sd_dhcp_client
*client
, int error
) {
229 log_dhcp_client(client
, "STOPPED: %s", strerror(-error
));
232 case DHCP_EVENT_STOP
:
233 log_dhcp_client(client
, "STOPPED");
235 case DHCP_EVENT_NO_LEASE
:
236 log_dhcp_client(client
, "STOPPED: No lease");
239 log_dhcp_client(client
, "STOPPED: Unknown reason");
244 client_notify(client
, error
);
246 client_initialize(client
);
249 static int client_message_init(sd_dhcp_client
*client
, DHCPPacket
**ret
,
250 uint8_t type
, size_t *_optlen
, size_t *_optoffset
) {
251 _cleanup_free_ DHCPPacket
*packet
;
252 size_t optlen
, optoffset
, size
;
257 assert(client
->secs
);
261 assert(type
== DHCP_DISCOVER
|| type
== DHCP_REQUEST
);
263 optlen
= DHCP_MIN_OPTIONS_SIZE
;
264 size
= sizeof(DHCPPacket
) + optlen
;
266 packet
= malloc0(size
);
270 r
= dhcp_message_init(&packet
->dhcp
, BOOTREQUEST
, client
->xid
, type
,
275 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
276 refuse to issue an DHCP lease if 'secs' is set to zero */
277 packet
->dhcp
.secs
= htobe16(client
->secs
);
279 /* RFC2132 section 4.1
280 A client that cannot receive unicast IP datagrams until its protocol
281 software has been configured with an IP address SHOULD set the
282 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
283 DHCPREQUEST messages that client sends. The BROADCAST bit will
284 provide a hint to the DHCP server and BOOTP relay agent to broadcast
285 any messages to the client on the client's subnet. */
286 packet
->dhcp
.flags
= htobe16(0x8000);
288 /* RFC2132 section 4.1.1:
289 The client MUST include its hardware address in the ’chaddr’ field, if
290 necessary for delivery of DHCP reply messages.
292 memcpy(&packet
->dhcp
.chaddr
, &client
->client_id
.mac_addr
, ETH_ALEN
);
294 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
295 Identifier option is not set */
296 r
= dhcp_option_append(&packet
->dhcp
, optlen
, &optoffset
, 0,
297 DHCP_OPTION_CLIENT_IDENTIFIER
,
298 sizeof(client
->client_id
), &client
->client_id
);
303 /* RFC2131 section 3.5:
304 in its initial DHCPDISCOVER or DHCPREQUEST message, a
305 client may provide the server with a list of specific
306 parameters the client is interested in. If the client
307 includes a list of parameters in a DHCPDISCOVER message,
308 it MUST include that list in any subsequent DHCPREQUEST
311 r
= dhcp_option_append(&packet
->dhcp
, optlen
, &optoffset
, 0,
312 DHCP_OPTION_PARAMETER_REQUEST_LIST
,
313 client
->req_opts_size
, client
->req_opts
);
317 /* RFC2131 section 3.5:
318 The client SHOULD include the ’maximum DHCP message size’ option to
319 let the server know how large the server may make its DHCP messages.
321 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
322 than the defined default size unless the Maximum Messge Size option
325 max_size
= htobe16(size
);
326 r
= dhcp_option_append(&packet
->dhcp
, optlen
, &optoffset
, 0,
327 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
,
333 *_optoffset
= optoffset
;
340 static int dhcp_client_send_raw(sd_dhcp_client
*client
, DHCPPacket
*packet
,
342 dhcp_packet_append_ip_headers(packet
, INADDR_ANY
, DHCP_PORT_CLIENT
,
343 INADDR_BROADCAST
, DHCP_PORT_SERVER
, len
);
345 return dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
349 static int client_send_discover(sd_dhcp_client
*client
) {
350 _cleanup_free_ DHCPPacket
*discover
= NULL
;
351 size_t optoffset
, optlen
;
356 assert(client
->state
== DHCP_STATE_INIT
||
357 client
->state
== DHCP_STATE_SELECTING
);
359 /* See RFC2131 section 4.4.1 */
361 r
= sd_event_now(client
->event
, CLOCK_MONOTONIC
, &time_now
);
364 assert(time_now
>= client
->start_time
);
366 /* seconds between sending first and last DISCOVER
367 * must always be strictly positive to deal with broken servers */
368 client
->secs
= ((time_now
- client
->start_time
) / USEC_PER_SEC
) ? : 1;
370 r
= client_message_init(client
, &discover
, DHCP_DISCOVER
,
371 &optlen
, &optoffset
);
375 /* the client may suggest values for the network address
376 and lease time in the DHCPDISCOVER message. The client may include
377 the ’requested IP address’ option to suggest that a particular IP
378 address be assigned, and may include the ’IP address lease time’
379 option to suggest the lease time it would like.
381 if (client
->last_addr
!= INADDR_ANY
) {
382 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
383 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
384 4, &client
->last_addr
);
389 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
390 DHCP_OPTION_END
, 0, NULL
);
394 /* We currently ignore:
395 The client SHOULD wait a random time between one and ten seconds to
396 desynchronize the use of DHCP at startup.
398 r
= dhcp_client_send_raw(client
, discover
, sizeof(DHCPPacket
) + optoffset
);
402 log_dhcp_client(client
, "DISCOVER");
407 static int client_send_request(sd_dhcp_client
*client
) {
408 _cleanup_free_ DHCPPacket
*request
= NULL
;
409 size_t optoffset
, optlen
;
412 r
= client_message_init(client
, &request
, DHCP_REQUEST
,
413 &optlen
, &optoffset
);
417 switch (client
->state
) {
418 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
419 SELECTING should be REQUESTING)
422 case DHCP_STATE_REQUESTING
:
423 /* Client inserts the address of the selected server in ’server
424 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
425 filled in with the yiaddr value from the chosen DHCPOFFER.
428 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
429 DHCP_OPTION_SERVER_IDENTIFIER
,
430 4, &client
->lease
->server_address
);
434 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
435 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
436 4, &client
->lease
->address
);
442 case DHCP_STATE_INIT_REBOOT
:
443 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
444 option MUST be filled in with client’s notion of its previously
445 assigned address. ’ciaddr’ MUST be zero.
447 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
448 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
449 4, &client
->last_addr
);
454 case DHCP_STATE_RENEWING
:
455 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
456 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
457 client’s IP address.
461 case DHCP_STATE_REBINDING
:
462 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
463 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
464 client’s IP address.
466 This message MUST be broadcast to the 0xffffffff IP broadcast address.
468 request
->dhcp
.ciaddr
= client
->lease
->address
;
472 case DHCP_STATE_INIT
:
473 case DHCP_STATE_SELECTING
:
474 case DHCP_STATE_REBOOTING
:
475 case DHCP_STATE_BOUND
:
476 case DHCP_STATE_STOPPED
:
480 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
481 DHCP_OPTION_END
, 0, NULL
);
485 if (client
->state
== DHCP_STATE_RENEWING
) {
486 r
= dhcp_network_send_udp_socket(client
->fd
,
487 client
->lease
->server_address
,
490 sizeof(DHCPMessage
) + optoffset
);
492 r
= dhcp_client_send_raw(client
, request
, sizeof(DHCPPacket
) + optoffset
);
497 switch (client
->state
) {
498 case DHCP_STATE_REQUESTING
:
499 log_dhcp_client(client
, "REQUEST (requesting)");
501 case DHCP_STATE_INIT_REBOOT
:
502 log_dhcp_client(client
, "REQUEST (init-reboot)");
504 case DHCP_STATE_RENEWING
:
505 log_dhcp_client(client
, "REQUEST (renewing)");
507 case DHCP_STATE_REBINDING
:
508 log_dhcp_client(client
, "REQUEST (rebinding)");
511 log_dhcp_client(client
, "REQUEST (invalid)");
518 static int client_start(sd_dhcp_client
*client
);
520 static int client_timeout_resend(sd_event_source
*s
, uint64_t usec
,
522 sd_dhcp_client
*client
= userdata
;
523 DHCP_CLIENT_DONT_DESTROY(client
);
524 usec_t next_timeout
= 0;
531 assert(client
->event
);
533 r
= sd_event_now(client
->event
, CLOCK_MONOTONIC
, &time_now
);
537 switch (client
->state
) {
538 case DHCP_STATE_RENEWING
:
540 time_left
= (client
->lease
->t2
- client
->lease
->t1
) / 2;
544 next_timeout
= time_now
+ time_left
* USEC_PER_SEC
;
548 case DHCP_STATE_REBINDING
:
550 time_left
= (client
->lease
->lifetime
- client
->lease
->t2
) / 2;
554 next_timeout
= time_now
+ time_left
* USEC_PER_SEC
;
557 case DHCP_STATE_REBOOTING
:
558 /* start over as we did not receive a timely ack or nak */
559 r
= client_initialize(client
);
563 r
= client_start(client
);
567 log_dhcp_client(client
, "REBOOTED");
571 case DHCP_STATE_INIT
:
572 case DHCP_STATE_INIT_REBOOT
:
573 case DHCP_STATE_SELECTING
:
574 case DHCP_STATE_REQUESTING
:
575 case DHCP_STATE_BOUND
:
577 if (client
->attempt
< 64)
578 client
->attempt
*= 2;
580 next_timeout
= time_now
+ (client
->attempt
- 1) * USEC_PER_SEC
;
584 case DHCP_STATE_STOPPED
:
589 next_timeout
+= (random_u32() & 0x1fffff);
591 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
593 r
= sd_event_add_time(client
->event
,
594 &client
->timeout_resend
,
596 next_timeout
, 10 * USEC_PER_MSEC
,
597 client_timeout_resend
, client
);
601 r
= sd_event_source_set_priority(client
->timeout_resend
,
602 client
->event_priority
);
606 switch (client
->state
) {
607 case DHCP_STATE_INIT
:
608 r
= client_send_discover(client
);
610 client
->state
= DHCP_STATE_SELECTING
;
613 if (client
->attempt
>= 64)
619 case DHCP_STATE_SELECTING
:
620 r
= client_send_discover(client
);
621 if (r
< 0 && client
->attempt
>= 64)
626 case DHCP_STATE_INIT_REBOOT
:
627 case DHCP_STATE_REQUESTING
:
628 case DHCP_STATE_RENEWING
:
629 case DHCP_STATE_REBINDING
:
630 r
= client_send_request(client
);
631 if (r
< 0 && client
->attempt
>= 64)
634 if (client
->state
== DHCP_STATE_INIT_REBOOT
)
635 client
->state
= DHCP_STATE_REBOOTING
;
637 client
->request_sent
= time_now
;
641 case DHCP_STATE_REBOOTING
:
642 case DHCP_STATE_BOUND
:
646 case DHCP_STATE_STOPPED
:
654 client_stop(client
, r
);
656 /* Errors were dealt with when stopping the client, don't spill
657 errors into the event loop handler */
661 static int client_initialize_events(sd_dhcp_client
*client
,
662 sd_event_io_handler_t io_callback
) {
666 assert(client
->event
);
668 r
= sd_event_add_io(client
->event
, &client
->receive_message
,
669 client
->fd
, EPOLLIN
, io_callback
,
674 r
= sd_event_source_set_priority(client
->receive_message
,
675 client
->event_priority
);
679 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
681 r
= sd_event_add_time(client
->event
,
682 &client
->timeout_resend
,
685 client_timeout_resend
, client
);
689 r
= sd_event_source_set_priority(client
->timeout_resend
,
690 client
->event_priority
);
694 client_stop(client
, r
);
700 static int client_start(sd_dhcp_client
*client
) {
703 assert_return(client
, -EINVAL
);
704 assert_return(client
->event
, -EINVAL
);
705 assert_return(client
->index
> 0, -EINVAL
);
706 assert_return(client
->fd
< 0, -EBUSY
);
707 assert_return(client
->xid
== 0, -EINVAL
);
708 assert_return(client
->state
== DHCP_STATE_INIT
||
709 client
->state
== DHCP_STATE_INIT_REBOOT
, -EBUSY
);
711 client
->xid
= random_u32();
713 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
, client
->xid
);
715 client_stop(client
, r
);
720 if (client
->state
== DHCP_STATE_INIT
) {
721 client
->start_time
= now(CLOCK_MONOTONIC
);
725 return client_initialize_events(client
, client_receive_message_raw
);
728 static int client_timeout_expire(sd_event_source
*s
, uint64_t usec
,
730 sd_dhcp_client
*client
= userdata
;
731 DHCP_CLIENT_DONT_DESTROY(client
);
733 log_dhcp_client(client
, "EXPIRED");
735 client_notify(client
, DHCP_EVENT_EXPIRED
);
737 /* lease was lost, start over if not freed or stopped in callback */
738 if (client
->state
!= DHCP_STATE_STOPPED
) {
739 client_initialize(client
);
740 client_start(client
);
746 static int client_timeout_t2(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
747 sd_dhcp_client
*client
= userdata
;
748 DHCP_CLIENT_DONT_DESTROY(client
);
751 client
->receive_message
= sd_event_source_unref(client
->receive_message
);
752 client
->fd
= asynchronous_close(client
->fd
);
754 client
->state
= DHCP_STATE_REBINDING
;
757 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
, client
->xid
);
759 client_stop(client
, r
);
764 return client_initialize_events(client
, client_receive_message_raw
);
767 static int client_timeout_t1(sd_event_source
*s
, uint64_t usec
,
769 sd_dhcp_client
*client
= userdata
;
770 DHCP_CLIENT_DONT_DESTROY(client
);
773 client
->state
= DHCP_STATE_RENEWING
;
776 r
= dhcp_network_bind_udp_socket(client
->lease
->address
,
779 log_dhcp_client(client
, "could not bind UDP socket");
785 return client_initialize_events(client
, client_receive_message_udp
);
788 static int client_handle_offer(sd_dhcp_client
*client
, DHCPMessage
*offer
,
790 _cleanup_dhcp_lease_unref_ sd_dhcp_lease
*lease
= NULL
;
793 r
= dhcp_lease_new(&lease
);
797 r
= dhcp_option_parse(offer
, len
, dhcp_lease_parse_options
, lease
);
798 if (r
!= DHCP_OFFER
) {
799 log_dhcp_client(client
, "receieved message was not an OFFER, ignoring");
803 lease
->next_server
= offer
->siaddr
;
805 lease
->address
= offer
->yiaddr
;
807 if (lease
->address
== INADDR_ANY
||
808 lease
->server_address
== INADDR_ANY
||
809 lease
->lifetime
== 0) {
810 log_dhcp_client(client
, "receieved lease lacks address, server "
811 "address or lease lifetime, ignoring");
815 if (lease
->subnet_mask
== INADDR_ANY
) {
816 r
= dhcp_lease_set_default_subnet_mask(lease
);
818 log_dhcp_client(client
, "receieved lease lacks subnet "
819 "mask, and a fallback one can not be "
820 "generated, ignoring");
825 sd_dhcp_lease_unref(client
->lease
);
826 client
->lease
= lease
;
829 log_dhcp_client(client
, "OFFER");
834 static int client_handle_ack(sd_dhcp_client
*client
, DHCPMessage
*ack
,
836 _cleanup_dhcp_lease_unref_ sd_dhcp_lease
*lease
= NULL
;
839 r
= dhcp_lease_new(&lease
);
843 r
= dhcp_option_parse(ack
, len
, dhcp_lease_parse_options
, lease
);
845 log_dhcp_client(client
, "NAK");
846 return DHCP_EVENT_NO_LEASE
;
850 log_dhcp_client(client
, "receieved message was not an ACK, ignoring");
854 lease
->next_server
= ack
->siaddr
;
856 lease
->address
= ack
->yiaddr
;
858 if (lease
->address
== INADDR_ANY
||
859 lease
->server_address
== INADDR_ANY
||
860 lease
->lifetime
== 0) {
861 log_dhcp_client(client
, "receieved lease lacks address, server "
862 "address or lease lifetime, ignoring");
866 if (lease
->subnet_mask
== INADDR_ANY
) {
867 r
= dhcp_lease_set_default_subnet_mask(lease
);
869 log_dhcp_client(client
, "receieved lease lacks subnet "
870 "mask, and a fallback one can not be "
871 "generated, ignoring");
876 r
= DHCP_EVENT_IP_ACQUIRE
;
878 if (client
->lease
->address
!= lease
->address
||
879 client
->lease
->subnet_mask
!= lease
->subnet_mask
||
880 client
->lease
->router
!= lease
->router
) {
881 r
= DHCP_EVENT_IP_CHANGE
;
883 r
= DHCP_EVENT_RENEW
;
885 client
->lease
= sd_dhcp_lease_unref(client
->lease
);
888 client
->lease
= lease
;
891 log_dhcp_client(client
, "ACK");
896 static uint64_t client_compute_timeout(sd_dhcp_client
*client
,
897 uint32_t lifetime
, double factor
) {
899 assert(client
->request_sent
);
902 return client
->request_sent
+ ((lifetime
- 3) * USEC_PER_SEC
* factor
) +
903 + (random_u32() & 0x1fffff);
906 static int client_set_lease_timeouts(sd_dhcp_client
*client
) {
908 uint64_t lifetime_timeout
;
911 char time_string
[FORMAT_TIMESPAN_MAX
];
915 assert(client
->event
);
916 assert(client
->lease
);
917 assert(client
->lease
->lifetime
);
919 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
920 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
921 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
923 /* don't set timers for infinite leases */
924 if (client
->lease
->lifetime
== 0xffffffff)
927 r
= sd_event_now(client
->event
, CLOCK_MONOTONIC
, &time_now
);
930 assert(client
->request_sent
<= time_now
);
932 /* convert the various timeouts from relative (secs) to absolute (usecs) */
933 lifetime_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 1);
934 if (client
->lease
->t1
&& client
->lease
->t2
) {
935 /* both T1 and T2 are given */
936 if (client
->lease
->t1
< client
->lease
->t2
&&
937 client
->lease
->t2
< client
->lease
->lifetime
) {
938 /* they are both valid */
939 t2_timeout
= client_compute_timeout(client
, client
->lease
->t2
, 1);
940 t1_timeout
= client_compute_timeout(client
, client
->lease
->t1
, 1);
943 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
944 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
945 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
946 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
948 } else if (client
->lease
->t2
&& client
->lease
->t2
< client
->lease
->lifetime
) {
949 /* only T2 is given, and it is valid */
950 t2_timeout
= client_compute_timeout(client
, client
->lease
->t2
, 1);
951 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
952 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
953 if (t2_timeout
<= t1_timeout
) {
954 /* the computed T1 would be invalid, so discard T2 */
955 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
956 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
958 } else if (client
->lease
->t1
&& client
->lease
->t1
< client
->lease
->lifetime
) {
959 /* only T1 is given, and it is valid */
960 t1_timeout
= client_compute_timeout(client
, client
->lease
->t1
, 1);
961 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
962 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
963 if (t2_timeout
<= t1_timeout
) {
964 /* the computed T2 would be invalid, so discard T1 */
965 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
966 client
->lease
->t2
= client
->lease
->lifetime
/ 2;
969 /* fall back to the default timeouts */
970 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
971 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
972 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
973 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
976 /* arm lifetime timeout */
977 r
= sd_event_add_time(client
->event
, &client
->timeout_expire
,
979 lifetime_timeout
, 10 * USEC_PER_MSEC
,
980 client_timeout_expire
, client
);
984 r
= sd_event_source_set_priority(client
->timeout_expire
,
985 client
->event_priority
);
989 log_dhcp_client(client
, "lease expires in %s",
990 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
,
991 lifetime_timeout
- time_now
, 0));
993 /* don't arm earlier timeouts if this has already expired */
994 if (lifetime_timeout
<= time_now
)
998 r
= sd_event_add_time(client
->event
,
1003 client_timeout_t2
, client
);
1007 r
= sd_event_source_set_priority(client
->timeout_t2
,
1008 client
->event_priority
);
1012 log_dhcp_client(client
, "T2 expires in %s",
1013 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
,
1014 t2_timeout
- time_now
, 0));
1016 /* don't arm earlier timeout if this has already expired */
1017 if (t2_timeout
<= time_now
)
1020 /* arm T1 timeout */
1021 r
= sd_event_add_time(client
->event
,
1022 &client
->timeout_t1
,
1024 t1_timeout
, 10 * USEC_PER_MSEC
,
1025 client_timeout_t1
, client
);
1029 r
= sd_event_source_set_priority(client
->timeout_t1
,
1030 client
->event_priority
);
1034 log_dhcp_client(client
, "T1 expires in %s",
1035 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
,
1036 t1_timeout
- time_now
, 0));
1041 static int client_handle_message(sd_dhcp_client
*client
, DHCPMessage
*message
,
1043 DHCP_CLIENT_DONT_DESTROY(client
);
1044 int r
= 0, notify_event
= 0;
1047 assert(client
->event
);
1050 if (be32toh(message
->magic
) != DHCP_MAGIC_COOKIE
) {
1051 log_dhcp_client(client
, "not a DHCP message: ignoring");
1055 if (message
->op
!= BOOTREPLY
) {
1056 log_dhcp_client(client
, "not a BOOTREPLY message: ignoring");
1060 if (be32toh(message
->xid
) != client
->xid
) {
1061 log_dhcp_client(client
, "received xid (%u) does not match "
1062 "expected (%u): ignoring",
1063 be32toh(message
->xid
), client
->xid
);
1067 if (message
->htype
!= ARPHRD_ETHER
|| message
->hlen
!= ETHER_ADDR_LEN
) {
1068 log_dhcp_client(client
, "not an ethernet packet");
1072 if (memcmp(&message
->chaddr
[0], &client
->client_id
.mac_addr
,
1074 log_dhcp_client(client
, "received chaddr does not match "
1075 "expected: ignoring");
1079 switch (client
->state
) {
1080 case DHCP_STATE_SELECTING
:
1082 r
= client_handle_offer(client
, message
, len
);
1085 client
->timeout_resend
=
1086 sd_event_source_unref(client
->timeout_resend
);
1088 client
->state
= DHCP_STATE_REQUESTING
;
1089 client
->attempt
= 1;
1091 r
= sd_event_add_time(client
->event
,
1092 &client
->timeout_resend
,
1095 client_timeout_resend
, client
);
1099 r
= sd_event_source_set_priority(client
->timeout_resend
,
1100 client
->event_priority
);
1103 } else if (r
== -ENOMSG
)
1104 /* invalid message, let's ignore it */
1109 case DHCP_STATE_REBOOTING
:
1110 case DHCP_STATE_REQUESTING
:
1111 case DHCP_STATE_RENEWING
:
1112 case DHCP_STATE_REBINDING
:
1114 r
= client_handle_ack(client
, message
, len
);
1115 if (r
== DHCP_EVENT_NO_LEASE
) {
1117 client
->timeout_resend
=
1118 sd_event_source_unref(client
->timeout_resend
);
1120 if (client
->state
== DHCP_STATE_REBOOTING
) {
1121 r
= client_initialize(client
);
1125 r
= client_start(client
);
1129 log_dhcp_client(client
, "REBOOTED");
1133 } else if (r
>= 0) {
1134 client
->timeout_resend
=
1135 sd_event_source_unref(client
->timeout_resend
);
1137 if (IN_SET(client
->state
, DHCP_STATE_REQUESTING
,
1138 DHCP_STATE_REBOOTING
))
1139 notify_event
= DHCP_EVENT_IP_ACQUIRE
;
1140 else if (r
!= DHCP_EVENT_IP_ACQUIRE
)
1143 client
->state
= DHCP_STATE_BOUND
;
1144 client
->attempt
= 1;
1146 client
->last_addr
= client
->lease
->address
;
1148 r
= client_set_lease_timeouts(client
);
1153 client_notify(client
, notify_event
);
1154 if (client
->state
== DHCP_STATE_STOPPED
)
1158 client
->receive_message
=
1159 sd_event_source_unref(client
->receive_message
);
1160 client
->fd
= asynchronous_close(client
->fd
);
1161 } else if (r
== -ENOMSG
)
1162 /* invalid message, let's ignore it */
1167 case DHCP_STATE_INIT
:
1168 case DHCP_STATE_INIT_REBOOT
:
1169 case DHCP_STATE_BOUND
:
1173 case DHCP_STATE_STOPPED
:
1179 if (r
< 0 || r
== DHCP_EVENT_NO_LEASE
)
1180 client_stop(client
, r
);
1185 static int client_receive_message_udp(sd_event_source
*s
, int fd
,
1186 uint32_t revents
, void *userdata
) {
1187 sd_dhcp_client
*client
= userdata
;
1188 _cleanup_free_ DHCPMessage
*message
= NULL
;
1189 int buflen
= 0, len
, r
;
1194 r
= ioctl(fd
, FIONREAD
, &buflen
);
1199 /* this can't be right */
1202 message
= malloc0(buflen
);
1206 len
= read(fd
, message
, buflen
);
1208 log_dhcp_client(client
, "could not receive message from UDP "
1211 } else if ((size_t)len
< sizeof(DHCPMessage
))
1214 return client_handle_message(client
, message
, len
);
1217 static int client_receive_message_raw(sd_event_source
*s
, int fd
,
1218 uint32_t revents
, void *userdata
) {
1219 sd_dhcp_client
*client
= userdata
;
1220 _cleanup_free_ DHCPPacket
*packet
= NULL
;
1221 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct tpacket_auxdata
))];
1222 struct iovec iov
= {};
1223 struct msghdr msg
= {
1226 .msg_control
= cmsgbuf
,
1227 .msg_controllen
= sizeof(cmsgbuf
),
1229 struct cmsghdr
*cmsg
;
1230 bool checksum
= true;
1231 int buflen
= 0, len
, r
;
1236 r
= ioctl(fd
, FIONREAD
, &buflen
);
1241 /* this can't be right */
1244 packet
= malloc0(buflen
);
1248 iov
.iov_base
= packet
;
1249 iov
.iov_len
= buflen
;
1251 len
= recvmsg(fd
, &msg
, 0);
1253 log_dhcp_client(client
, "could not receive message from raw "
1256 } else if ((size_t)len
< sizeof(DHCPPacket
))
1259 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
1260 if (cmsg
->cmsg_level
== SOL_PACKET
&&
1261 cmsg
->cmsg_type
== PACKET_AUXDATA
&&
1262 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct tpacket_auxdata
))) {
1263 struct tpacket_auxdata
*aux
= (struct tpacket_auxdata
*)CMSG_DATA(cmsg
);
1265 checksum
= !(aux
->tp_status
& TP_STATUS_CSUMNOTREADY
);
1270 r
= dhcp_packet_verify_headers(packet
, len
, checksum
);
1274 len
-= DHCP_IP_UDP_SIZE
;
1276 return client_handle_message(client
, &packet
->dhcp
, len
);
1279 int sd_dhcp_client_start(sd_dhcp_client
*client
) {
1282 assert_return(client
, -EINVAL
);
1284 r
= client_initialize(client
);
1288 if (client
->last_addr
)
1289 client
->state
= DHCP_STATE_INIT_REBOOT
;
1291 r
= client_start(client
);
1293 log_dhcp_client(client
, "STARTED on ifindex %u with address %s",
1295 ether_ntoa(&client
->client_id
.mac_addr
));
1300 int sd_dhcp_client_stop(sd_dhcp_client
*client
) {
1301 DHCP_CLIENT_DONT_DESTROY(client
);
1303 assert_return(client
, -EINVAL
);
1305 client_stop(client
, DHCP_EVENT_STOP
);
1306 client
->state
= DHCP_STATE_STOPPED
;
1311 int sd_dhcp_client_attach_event(sd_dhcp_client
*client
, sd_event
*event
,
1315 assert_return(client
, -EINVAL
);
1316 assert_return(!client
->event
, -EBUSY
);
1319 client
->event
= sd_event_ref(event
);
1321 r
= sd_event_default(&client
->event
);
1326 client
->event_priority
= priority
;
1331 int sd_dhcp_client_detach_event(sd_dhcp_client
*client
) {
1332 assert_return(client
, -EINVAL
);
1334 client
->event
= sd_event_unref(client
->event
);
1339 sd_event
*sd_dhcp_client_get_event(sd_dhcp_client
*client
) {
1343 return client
->event
;
1346 sd_dhcp_client
*sd_dhcp_client_ref(sd_dhcp_client
*client
) {
1348 assert_se(REFCNT_INC(client
->n_ref
) >= 2);
1353 sd_dhcp_client
*sd_dhcp_client_unref(sd_dhcp_client
*client
) {
1354 if (client
&& REFCNT_DEC(client
->n_ref
) <= 0) {
1355 log_dhcp_client(client
, "FREE");
1357 client_initialize(client
);
1359 client
->receive_message
=
1360 sd_event_source_unref(client
->receive_message
);
1362 sd_dhcp_client_detach_event(client
);
1364 sd_dhcp_lease_unref(client
->lease
);
1366 free(client
->req_opts
);
1373 int sd_dhcp_client_new(sd_dhcp_client
**ret
) {
1374 _cleanup_dhcp_client_unref_ sd_dhcp_client
*client
= NULL
;
1376 assert_return(ret
, -EINVAL
);
1378 client
= new0(sd_dhcp_client
, 1);
1382 client
->n_ref
= REFCNT_INIT
;
1383 client
->state
= DHCP_STATE_INIT
;
1386 client
->attempt
= 1;
1388 client
->req_opts_size
= ELEMENTSOF(default_req_opts
);
1390 client
->req_opts
= memdup(default_req_opts
, client
->req_opts_size
);
1391 if (!client
->req_opts
)