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>
34 #include "dhcp-protocol.h"
35 #include "dhcp-internal.h"
36 #include "dhcp-lease-internal.h"
37 #include "sd-dhcp-client.h"
39 struct sd_dhcp_client {
45 sd_event_source *timeout_resend;
48 union sockaddr_union link;
49 sd_event_source *receive_message;
51 size_t req_opts_allocated;
56 struct ether_addr mac_addr;
63 sd_event_source *timeout_t1;
64 sd_event_source *timeout_t2;
65 sd_event_source *timeout_expire;
66 sd_dhcp_client_cb_t cb;
71 static const uint8_t default_req_opts[] = {
72 DHCP_OPTION_SUBNET_MASK,
74 DHCP_OPTION_HOST_NAME,
75 DHCP_OPTION_DOMAIN_NAME,
76 DHCP_OPTION_DOMAIN_NAME_SERVER,
77 DHCP_OPTION_NTP_SERVER,
80 static int client_receive_message_raw(sd_event_source *s, int fd,
81 uint32_t revents, void *userdata);
82 static int client_receive_message_udp(sd_event_source *s, int fd,
83 uint32_t revents, void *userdata);
84 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error);
86 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
88 assert_return(client, -EINVAL);
91 client->userdata = userdata;
96 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
99 assert_return(client, -EINVAL);
100 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
101 DHCP_STATE_STOPPED), -EBUSY);
104 case DHCP_OPTION_PAD:
105 case DHCP_OPTION_OVERLOAD:
106 case DHCP_OPTION_MESSAGE_TYPE:
107 case DHCP_OPTION_PARAMETER_REQUEST_LIST:
108 case DHCP_OPTION_END:
115 for (i = 0; i < client->req_opts_size; i++)
116 if (client->req_opts[i] == option)
119 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
120 client->req_opts_size + 1))
123 client->req_opts[client->req_opts_size++] = option;
128 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
129 const struct in_addr *last_addr) {
130 assert_return(client, -EINVAL);
131 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
132 DHCP_STATE_STOPPED), -EBUSY);
135 client->last_addr = last_addr->s_addr;
137 client->last_addr = INADDR_ANY;
142 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
143 assert_return(client, -EINVAL);
144 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
145 DHCP_STATE_STOPPED), -EBUSY);
146 assert_return(interface_index > 0, -EINVAL);
148 client->index = interface_index;
153 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
154 const struct ether_addr *addr) {
155 bool need_restart = false;
157 assert_return(client, -EINVAL);
158 assert_return(addr, -EINVAL);
160 if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
163 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
164 log_dhcp_client(client, "Changing MAC address on running DHCP "
165 "client, restarting");
167 client = client_stop(client, DHCP_EVENT_STOP);
173 memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
174 client->client_id.type = 0x01;
176 if (need_restart && client->state != DHCP_STATE_STOPPED)
177 sd_dhcp_client_start(client);
182 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
183 assert_return(client, -EINVAL);
184 assert_return(ret, -EINVAL);
186 if (client->state != DHCP_STATE_BOUND &&
187 client->state != DHCP_STATE_RENEWING &&
188 client->state != DHCP_STATE_REBINDING)
189 return -EADDRNOTAVAIL;
191 *ret = sd_dhcp_lease_ref(client->lease);
196 static sd_dhcp_client *client_notify(sd_dhcp_client *client, int event) {
198 client = sd_dhcp_client_ref(client);
199 client->cb(client, event, client->userdata);
200 client = sd_dhcp_client_unref(client);
206 static int client_initialize(sd_dhcp_client *client) {
207 assert_return(client, -EINVAL);
209 client->receive_message =
210 sd_event_source_unref(client->receive_message);
212 client->fd = safe_close(client->fd);
214 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
216 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
217 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
218 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
222 client->state = DHCP_STATE_INIT;
226 client->lease = sd_dhcp_lease_unref(client->lease);
231 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error) {
232 assert_return(client, NULL);
235 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
238 case DHCP_EVENT_STOP:
239 log_dhcp_client(client, "STOPPED: Requested by user");
241 case DHCP_EVENT_NO_LEASE:
242 log_dhcp_client(client, "STOPPED: No lease");
245 log_dhcp_client(client, "STOPPED: Unknown reason");
250 client = client_notify(client, error);
253 client_initialize(client);
258 static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
259 uint8_t type, uint8_t **opt, size_t *optlen) {
264 assert(client->secs);
268 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
270 r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt,
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 message->secs = htobe16(client->secs);
279 /* RFC2132 section 4.1.1:
280 The client MUST include its hardware address in the ’chaddr’ field, if
281 necessary for delivery of DHCP reply messages.
283 memcpy(&message->chaddr, &client->client_id.mac_addr, ETH_ALEN);
285 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
286 Identifier option is not set */
287 r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
288 sizeof(client->client_id), &client->client_id);
293 /* RFC2131 section 3.5:
294 in its initial DHCPDISCOVER or DHCPREQUEST message, a
295 client may provide the server with a list of specific
296 parameters the client is interested in. If the client
297 includes a list of parameters in a DHCPDISCOVER message,
298 it MUST include that list in any subsequent DHCPREQUEST
301 r = dhcp_option_append(opt, optlen,
302 DHCP_OPTION_PARAMETER_REQUEST_LIST,
303 client->req_opts_size,
308 /* RFC2131 section 3.5:
309 The client SHOULD include the ’maximum DHCP message size’ option to
310 let the server know how large the server may make its DHCP messages.
312 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
313 than the defined default size unless the Maximum Messge Size option
316 max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
317 DHCP_MIN_OPTIONS_SIZE);
318 r = dhcp_option_append(opt, optlen,
319 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
327 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
329 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
330 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
332 return dhcp_network_send_raw_socket(client->fd, &client->link,
336 static int client_send_discover(sd_dhcp_client *client) {
337 _cleanup_free_ DHCPPacket *discover = NULL;
344 assert(client->state == DHCP_STATE_INIT ||
345 client->state == DHCP_STATE_SELECTING);
347 /* See RFC2131 section 4.4.1 */
349 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
352 assert(time_now >= client->start_time);
354 /* seconds between sending first and last DISCOVER
355 * must always be strictly positive to deal with broken servers */
356 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
358 optlen = DHCP_MIN_OPTIONS_SIZE;
359 len = sizeof(DHCPPacket) + optlen;
361 discover = malloc0(len);
365 r = client_message_init(client, &discover->dhcp, DHCP_DISCOVER,
370 /* the client may suggest values for the network address
371 and lease time in the DHCPDISCOVER message. The client may include
372 the ’requested IP address’ option to suggest that a particular IP
373 address be assigned, and may include the ’IP address lease time’
374 option to suggest the lease time it would like.
376 if (client->last_addr != INADDR_ANY) {
377 r = dhcp_option_append(&opt, &optlen,
378 DHCP_OPTION_REQUESTED_IP_ADDRESS,
379 4, &client->last_addr);
384 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
388 /* We currently ignore:
389 The client SHOULD wait a random time between one and ten seconds to
390 desynchronize the use of DHCP at startup.
392 r = dhcp_client_send_raw(client, discover, len - optlen);
396 log_dhcp_client(client, "DISCOVER");
401 static int client_send_request(sd_dhcp_client *client) {
402 _cleanup_free_ DHCPPacket *request;
407 optlen = DHCP_MIN_OPTIONS_SIZE;
408 len = sizeof(DHCPPacket) + optlen;
410 request = malloc0(len);
414 r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt,
419 switch (client->state) {
420 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
421 SELECTING should be REQUESTING)
424 case DHCP_STATE_REQUESTING:
425 /* Client inserts the address of the selected server in ’server
426 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
427 filled in with the yiaddr value from the chosen DHCPOFFER.
430 r = dhcp_option_append(&opt, &optlen,
431 DHCP_OPTION_SERVER_IDENTIFIER,
432 4, &client->lease->server_address);
436 r = dhcp_option_append(&opt, &optlen,
437 DHCP_OPTION_REQUESTED_IP_ADDRESS,
438 4, &client->lease->address);
444 case DHCP_STATE_INIT_REBOOT:
445 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
446 option MUST be filled in with client’s notion of its previously
447 assigned address. ’ciaddr’ MUST be zero.
449 r = dhcp_option_append(&opt, &optlen,
450 DHCP_OPTION_REQUESTED_IP_ADDRESS,
451 4, &client->last_addr);
456 case DHCP_STATE_RENEWING:
457 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
458 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
459 client’s IP address.
463 case DHCP_STATE_REBINDING:
464 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
465 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
466 client’s IP address.
468 This message MUST be broadcast to the 0xffffffff IP broadcast address.
470 request->dhcp.ciaddr = client->lease->address;
474 case DHCP_STATE_INIT:
475 case DHCP_STATE_SELECTING:
476 case DHCP_STATE_REBOOTING:
477 case DHCP_STATE_BOUND:
478 case DHCP_STATE_STOPPED:
482 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
486 if (client->state == DHCP_STATE_RENEWING) {
487 r = dhcp_network_send_udp_socket(client->fd,
488 client->lease->server_address,
491 len - optlen - DHCP_IP_UDP_SIZE);
493 r = dhcp_client_send_raw(client, request, len - optlen);
498 switch (client->state) {
499 case DHCP_STATE_REQUESTING:
500 log_dhcp_client(client, "REQUEST (requesting)");
502 case DHCP_STATE_INIT_REBOOT:
503 log_dhcp_client(client, "REQUEST (init-reboot)");
505 case DHCP_STATE_RENEWING:
506 log_dhcp_client(client, "REQUEST (renewing)");
508 case DHCP_STATE_REBINDING:
509 log_dhcp_client(client, "REQUEST (rebinding)");
512 log_dhcp_client(client, "REQUEST (invalid)");
519 static int client_start(sd_dhcp_client *client);
521 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
523 sd_dhcp_client *client = userdata;
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;
732 log_dhcp_client(client, "EXPIRED");
734 client = client_notify(client, DHCP_EVENT_EXPIRED);
736 /* lease was lost, start over if not freed or stopped in callback */
737 if (client && client->state != DHCP_STATE_STOPPED) {
738 client_initialize(client);
739 client_start(client);
745 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
746 sd_dhcp_client *client = userdata;
749 client->receive_message = sd_event_source_unref(client->receive_message);
750 client->fd = safe_close(client->fd);
752 client->state = DHCP_STATE_REBINDING;
755 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
757 client_stop(client, r);
762 return client_initialize_events(client, client_receive_message_raw);
765 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
767 sd_dhcp_client *client = userdata;
770 client->state = DHCP_STATE_RENEWING;
773 r = dhcp_network_bind_udp_socket(client->lease->address,
776 client_stop(client, r);
782 return client_initialize_events(client, client_receive_message_udp);
785 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
787 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
790 r = dhcp_lease_new(&lease);
794 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
795 if (r != DHCP_OFFER) {
796 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
800 lease->next_server = offer->siaddr;
802 lease->address = offer->yiaddr;
804 if (lease->address == INADDR_ANY ||
805 lease->server_address == INADDR_ANY ||
806 lease->lifetime == 0) {
807 log_dhcp_client(client, "receieved lease lacks address, server "
808 "address or lease lifetime, ignoring");
812 if (lease->subnet_mask == INADDR_ANY) {
813 r = dhcp_lease_set_default_subnet_mask(lease);
815 log_dhcp_client(client, "receieved lease lacks subnet "
816 "mask, and a fallback one can not be "
817 "generated, ignoring");
822 sd_dhcp_lease_unref(client->lease);
823 client->lease = lease;
826 log_dhcp_client(client, "OFFER");
831 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
833 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
836 r = dhcp_lease_new(&lease);
840 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
842 log_dhcp_client(client, "NAK");
843 return DHCP_EVENT_NO_LEASE;
847 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
851 lease->next_server = ack->siaddr;
853 lease->address = ack->yiaddr;
855 if (lease->address == INADDR_ANY ||
856 lease->server_address == INADDR_ANY ||
857 lease->lifetime == 0) {
858 log_dhcp_client(client, "receieved lease lacks address, server "
859 "address or lease lifetime, ignoring");
863 if (lease->subnet_mask == INADDR_ANY) {
864 r = dhcp_lease_set_default_subnet_mask(lease);
866 log_dhcp_client(client, "receieved lease lacks subnet "
867 "mask, and a fallback one can not be "
868 "generated, ignoring");
873 r = DHCP_EVENT_IP_ACQUIRE;
875 if (client->lease->address != lease->address ||
876 client->lease->subnet_mask != lease->subnet_mask ||
877 client->lease->router != lease->router) {
878 r = DHCP_EVENT_IP_CHANGE;
881 client->lease = sd_dhcp_lease_unref(client->lease);
884 client->lease = lease;
887 log_dhcp_client(client, "ACK");
892 static uint64_t client_compute_timeout(sd_dhcp_client *client,
893 uint32_t lifetime, double factor) {
895 assert(client->request_sent);
898 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
899 + (random_u32() & 0x1fffff);
902 static int client_set_lease_timeouts(sd_dhcp_client *client) {
904 uint64_t lifetime_timeout;
907 char time_string[FORMAT_TIMESPAN_MAX];
911 assert(client->event);
912 assert(client->lease);
913 assert(client->lease->lifetime);
915 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
916 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
917 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
919 /* don't set timers for infinite leases */
920 if (client->lease->lifetime == 0xffffffff)
923 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
926 assert(client->request_sent <= time_now);
928 /* convert the various timeouts from relative (secs) to absolute (usecs) */
929 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
930 if (client->lease->t1 && client->lease->t2) {
931 /* both T1 and T2 are given */
932 if (client->lease->t1 < client->lease->t2 &&
933 client->lease->t2 < client->lease->lifetime) {
934 /* they are both valid */
935 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
936 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
939 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
940 client->lease->t2 = (client->lease->lifetime * 7) / 8;
941 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
942 client->lease->t1 = client->lease->lifetime / 2;
944 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
945 /* only T2 is given, and it is valid */
946 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
947 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
948 client->lease->t1 = client->lease->lifetime / 2;
949 if (t2_timeout <= t1_timeout) {
950 /* the computed T1 would be invalid, so discard T2 */
951 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
952 client->lease->t2 = (client->lease->lifetime * 7) / 8;
954 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
955 /* only T1 is given, and it is valid */
956 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
957 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
958 client->lease->t2 = (client->lease->lifetime * 7) / 8;
959 if (t2_timeout <= t1_timeout) {
960 /* the computed T2 would be invalid, so discard T1 */
961 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
962 client->lease->t2 = client->lease->lifetime / 2;
965 /* fall back to the default timeouts */
966 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
967 client->lease->t1 = client->lease->lifetime / 2;
968 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
969 client->lease->t2 = (client->lease->lifetime * 7) / 8;
972 /* arm lifetime timeout */
973 r = sd_event_add_time(client->event, &client->timeout_expire,
975 lifetime_timeout, 10 * USEC_PER_MSEC,
976 client_timeout_expire, client);
980 r = sd_event_source_set_priority(client->timeout_expire,
981 client->event_priority);
985 log_dhcp_client(client, "lease expires in %s",
986 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
987 lifetime_timeout - time_now, 0));
989 /* don't arm earlier timeouts if this has already expired */
990 if (lifetime_timeout <= time_now)
994 r = sd_event_add_time(client->event,
999 client_timeout_t2, client);
1003 r = sd_event_source_set_priority(client->timeout_t2,
1004 client->event_priority);
1008 log_dhcp_client(client, "T2 expires in %s",
1009 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1010 t2_timeout - time_now, 0));
1012 /* don't arm earlier timeout if this has already expired */
1013 if (t2_timeout <= time_now)
1016 /* arm T1 timeout */
1017 r = sd_event_add_time(client->event,
1018 &client->timeout_t1,
1020 t1_timeout, 10 * USEC_PER_MSEC,
1021 client_timeout_t1, client);
1025 r = sd_event_source_set_priority(client->timeout_t1,
1026 client->event_priority);
1030 log_dhcp_client(client, "T1 expires in %s",
1031 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1032 t1_timeout - time_now, 0));
1037 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1039 int r = 0, notify_event = 0;
1042 assert(client->event);
1045 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1046 log_dhcp_client(client, "not a DHCP message: ignoring");
1050 if (message->op != BOOTREPLY) {
1051 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1055 if (be32toh(message->xid) != client->xid) {
1056 log_dhcp_client(client, "received xid (%u) does not match "
1057 "expected (%u): ignoring",
1058 be32toh(message->xid), client->xid);
1062 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1063 log_dhcp_client(client, "not an ethernet packet");
1067 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1069 log_dhcp_client(client, "received chaddr does not match "
1070 "expected: ignoring");
1074 switch (client->state) {
1075 case DHCP_STATE_SELECTING:
1077 r = client_handle_offer(client, message, len);
1080 client->timeout_resend =
1081 sd_event_source_unref(client->timeout_resend);
1083 client->state = DHCP_STATE_REQUESTING;
1084 client->attempt = 1;
1086 r = sd_event_add_time(client->event,
1087 &client->timeout_resend,
1090 client_timeout_resend, client);
1094 r = sd_event_source_set_priority(client->timeout_resend,
1095 client->event_priority);
1098 } else if (r == -ENOMSG)
1099 /* invalid message, let's ignore it */
1104 case DHCP_STATE_REBOOTING:
1105 case DHCP_STATE_REQUESTING:
1106 case DHCP_STATE_RENEWING:
1107 case DHCP_STATE_REBINDING:
1109 r = client_handle_ack(client, message, len);
1110 if (r == DHCP_EVENT_NO_LEASE) {
1112 client->timeout_resend =
1113 sd_event_source_unref(client->timeout_resend);
1115 if (client->state == DHCP_STATE_REBOOTING) {
1116 r = client_initialize(client);
1120 r = client_start(client);
1124 log_dhcp_client(client, "REBOOTED");
1128 } else if (r >= 0) {
1129 client->timeout_resend =
1130 sd_event_source_unref(client->timeout_resend);
1132 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1133 DHCP_STATE_REBOOTING))
1134 notify_event = DHCP_EVENT_IP_ACQUIRE;
1135 else if (r != DHCP_EVENT_IP_ACQUIRE)
1138 client->state = DHCP_STATE_BOUND;
1139 client->attempt = 1;
1141 client->last_addr = client->lease->address;
1143 r = client_set_lease_timeouts(client);
1148 client = client_notify(client, notify_event);
1150 client->state == DHCP_STATE_STOPPED)
1154 client->receive_message =
1155 sd_event_source_unref(client->receive_message);
1156 client->fd = safe_close(client->fd);
1157 } else if (r == -ENOMSG)
1158 /* invalid message, let's ignore it */
1163 case DHCP_STATE_INIT:
1164 case DHCP_STATE_INIT_REBOOT:
1165 case DHCP_STATE_BOUND:
1169 case DHCP_STATE_STOPPED:
1175 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1176 client_stop(client, r);
1181 static int client_receive_message_udp(sd_event_source *s, int fd,
1182 uint32_t revents, void *userdata) {
1183 sd_dhcp_client *client = userdata;
1184 _cleanup_free_ DHCPMessage *message = NULL;
1185 int buflen = 0, len, r;
1190 r = ioctl(fd, FIONREAD, &buflen);
1191 if (r < 0 || buflen <= 0)
1192 buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE;
1194 message = malloc0(buflen);
1198 len = read(fd, message, buflen);
1200 log_dhcp_client(client, "could not receive message from UDP "
1201 "socket: %s", strerror(errno));
1203 } else if ((size_t)len < sizeof(DHCPMessage))
1206 return client_handle_message(client, message, len);
1209 static int client_receive_message_raw(sd_event_source *s, int fd,
1210 uint32_t revents, void *userdata) {
1211 sd_dhcp_client *client = userdata;
1212 _cleanup_free_ DHCPPacket *packet = NULL;
1213 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1214 struct iovec iov = {};
1215 struct msghdr msg = {
1218 .msg_control = cmsgbuf,
1219 .msg_controllen = sizeof(cmsgbuf),
1221 struct cmsghdr *cmsg;
1222 bool checksum = true;
1223 int buflen = 0, len, r;
1228 r = ioctl(fd, FIONREAD, &buflen);
1229 if (r < 0 || buflen <= 0)
1230 buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE;
1232 packet = malloc0(buflen);
1236 iov.iov_base = packet;
1237 iov.iov_len = buflen;
1239 len = recvmsg(fd, &msg, 0);
1241 log_dhcp_client(client, "could not receive message from raw "
1242 "socket: %s", strerror(errno));
1244 } else if ((size_t)len < sizeof(DHCPPacket))
1247 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1248 if (cmsg->cmsg_level == SOL_PACKET &&
1249 cmsg->cmsg_type == PACKET_AUXDATA &&
1250 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1251 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1253 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1258 r = dhcp_packet_verify_headers(packet, len, checksum);
1262 len -= DHCP_IP_UDP_SIZE;
1264 return client_handle_message(client, &packet->dhcp, len);
1267 int sd_dhcp_client_start(sd_dhcp_client *client) {
1270 assert_return(client, -EINVAL);
1272 r = client_initialize(client);
1276 if (client->last_addr)
1277 client->state = DHCP_STATE_INIT_REBOOT;
1279 r = client_start(client);
1281 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1283 ether_ntoa(&client->client_id.mac_addr));
1288 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1289 assert_return(client, -EINVAL);
1291 if (client_stop(client, DHCP_EVENT_STOP))
1292 client->state = DHCP_STATE_STOPPED;
1297 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1301 assert_return(client, -EINVAL);
1302 assert_return(!client->event, -EBUSY);
1305 client->event = sd_event_ref(event);
1307 r = sd_event_default(&client->event);
1312 client->event_priority = priority;
1317 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1318 assert_return(client, -EINVAL);
1320 client->event = sd_event_unref(client->event);
1325 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1329 return client->event;
1332 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1334 assert_se(REFCNT_INC(client->n_ref) >= 2);
1339 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1340 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1341 log_dhcp_client(client, "UNREF");
1343 client_initialize(client);
1345 client->receive_message =
1346 sd_event_source_unref(client->receive_message);
1348 sd_dhcp_client_detach_event(client);
1350 sd_dhcp_lease_unref(client->lease);
1352 free(client->req_opts);
1361 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
1362 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1364 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1365 _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1367 assert_return(ret, -EINVAL);
1369 client = new0(sd_dhcp_client, 1);
1373 client->n_ref = REFCNT_INIT;
1374 client->state = DHCP_STATE_INIT;
1377 client->attempt = 1;
1379 client->req_opts_size = ELEMENTSOF(default_req_opts);
1381 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1382 if (!client->req_opts)