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 >= -1, -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);
234 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
236 client = client_notify(client, error);
239 client_initialize(client);
244 static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
245 uint8_t type, uint8_t **opt, size_t *optlen) {
250 assert(client->secs);
254 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
256 r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt,
261 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
262 refuse to issue an DHCP lease if 'secs' is set to zero */
263 message->secs = htobe16(client->secs);
265 /* RFC2132 section 4.1.1:
266 The client MUST include its hardware address in the ’chaddr’ field, if
267 necessary for delivery of DHCP reply messages.
269 memcpy(&message->chaddr, &client->client_id.mac_addr, ETH_ALEN);
271 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
272 Identifier option is not set */
273 r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
274 sizeof(client->client_id), &client->client_id);
279 /* RFC2131 section 3.5:
280 in its initial DHCPDISCOVER or DHCPREQUEST message, a
281 client may provide the server with a list of specific
282 parameters the client is interested in. If the client
283 includes a list of parameters in a DHCPDISCOVER message,
284 it MUST include that list in any subsequent DHCPREQUEST
287 r = dhcp_option_append(opt, optlen,
288 DHCP_OPTION_PARAMETER_REQUEST_LIST,
289 client->req_opts_size,
294 /* RFC2131 section 3.5:
295 The client SHOULD include the ’maximum DHCP message size’ option to
296 let the server know how large the server may make its DHCP messages.
298 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
299 than the defined default size unless the Maximum Messge Size option
302 max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
303 DHCP_MIN_OPTIONS_SIZE);
304 r = dhcp_option_append(opt, optlen,
305 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
313 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
315 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
316 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
318 return dhcp_network_send_raw_socket(client->fd, &client->link,
322 static int client_send_discover(sd_dhcp_client *client) {
323 _cleanup_free_ DHCPPacket *discover = NULL;
330 assert(client->state == DHCP_STATE_INIT ||
331 client->state == DHCP_STATE_SELECTING);
333 /* See RFC2131 section 4.4.1 */
335 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
338 assert(time_now >= client->start_time);
340 /* seconds between sending first and last DISCOVER
341 * must always be strictly positive to deal with broken servers */
342 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
344 optlen = DHCP_MIN_OPTIONS_SIZE;
345 len = sizeof(DHCPPacket) + optlen;
347 discover = malloc0(len);
351 r = client_message_init(client, &discover->dhcp, DHCP_DISCOVER,
356 /* the client may suggest values for the network address
357 and lease time in the DHCPDISCOVER message. The client may include
358 the ’requested IP address’ option to suggest that a particular IP
359 address be assigned, and may include the ’IP address lease time’
360 option to suggest the lease time it would like.
362 if (client->last_addr != INADDR_ANY) {
363 r = dhcp_option_append(&opt, &optlen,
364 DHCP_OPTION_REQUESTED_IP_ADDRESS,
365 4, &client->last_addr);
370 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
374 /* We currently ignore:
375 The client SHOULD wait a random time between one and ten seconds to
376 desynchronize the use of DHCP at startup.
378 r = dhcp_client_send_raw(client, discover, len - optlen);
382 log_dhcp_client(client, "DISCOVER");
387 static int client_send_request(sd_dhcp_client *client) {
388 _cleanup_free_ DHCPPacket *request;
393 optlen = DHCP_MIN_OPTIONS_SIZE;
394 len = sizeof(DHCPPacket) + optlen;
396 request = malloc0(len);
400 r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt,
405 switch (client->state) {
406 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
407 SELECTING should be REQUESTING)
410 case DHCP_STATE_REQUESTING:
411 /* Client inserts the address of the selected server in ’server
412 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
413 filled in with the yiaddr value from the chosen DHCPOFFER.
416 r = dhcp_option_append(&opt, &optlen,
417 DHCP_OPTION_SERVER_IDENTIFIER,
418 4, &client->lease->server_address);
422 r = dhcp_option_append(&opt, &optlen,
423 DHCP_OPTION_REQUESTED_IP_ADDRESS,
424 4, &client->lease->address);
430 case DHCP_STATE_INIT_REBOOT:
431 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
432 option MUST be filled in with client’s notion of its previously
433 assigned address. ’ciaddr’ MUST be zero.
435 r = dhcp_option_append(&opt, &optlen,
436 DHCP_OPTION_REQUESTED_IP_ADDRESS,
437 4, &client->last_addr);
442 case DHCP_STATE_RENEWING:
443 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
444 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
445 client’s IP address.
449 case DHCP_STATE_REBINDING:
450 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
451 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
452 client’s IP address.
454 This message MUST be broadcast to the 0xffffffff IP broadcast address.
456 request->dhcp.ciaddr = client->lease->address;
460 case DHCP_STATE_INIT:
461 case DHCP_STATE_SELECTING:
462 case DHCP_STATE_REBOOTING:
463 case DHCP_STATE_BOUND:
464 case DHCP_STATE_STOPPED:
468 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
472 if (client->state == DHCP_STATE_RENEWING) {
473 r = dhcp_network_send_udp_socket(client->fd,
474 client->lease->server_address,
477 len - optlen - DHCP_IP_UDP_SIZE);
479 r = dhcp_client_send_raw(client, request, len - optlen);
484 switch (client->state) {
485 case DHCP_STATE_REQUESTING:
486 log_dhcp_client(client, "REQUEST (requesting)");
488 case DHCP_STATE_INIT_REBOOT:
489 log_dhcp_client(client, "REQUEST (init-reboot)");
491 case DHCP_STATE_RENEWING:
492 log_dhcp_client(client, "REQUEST (renewing)");
494 case DHCP_STATE_REBINDING:
495 log_dhcp_client(client, "REQUEST (rebinding)");
498 log_dhcp_client(client, "REQUEST (invalid)");
505 static int client_start(sd_dhcp_client *client);
507 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
509 sd_dhcp_client *client = userdata;
510 usec_t next_timeout = 0;
517 assert(client->event);
519 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
523 switch (client->state) {
524 case DHCP_STATE_RENEWING:
526 time_left = (client->lease->t2 - client->lease->t1) / 2;
530 next_timeout = time_now + time_left * USEC_PER_SEC;
534 case DHCP_STATE_REBINDING:
536 time_left = (client->lease->lifetime - client->lease->t2) / 2;
540 next_timeout = time_now + time_left * USEC_PER_SEC;
543 case DHCP_STATE_REBOOTING:
544 /* start over as we did not receive a timely ack or nak */
545 r = client_initialize(client);
549 r = client_start(client);
553 log_dhcp_client(client, "REBOOTED");
557 case DHCP_STATE_INIT:
558 case DHCP_STATE_INIT_REBOOT:
559 case DHCP_STATE_SELECTING:
560 case DHCP_STATE_REQUESTING:
561 case DHCP_STATE_BOUND:
563 if (client->attempt < 64)
564 client->attempt *= 2;
566 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
570 case DHCP_STATE_STOPPED:
575 next_timeout += (random_u32() & 0x1fffff);
577 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
579 r = sd_event_add_time(client->event,
580 &client->timeout_resend,
582 next_timeout, 10 * USEC_PER_MSEC,
583 client_timeout_resend, client);
587 r = sd_event_source_set_priority(client->timeout_resend,
588 client->event_priority);
592 switch (client->state) {
593 case DHCP_STATE_INIT:
594 r = client_send_discover(client);
596 client->state = DHCP_STATE_SELECTING;
599 if (client->attempt >= 64)
605 case DHCP_STATE_SELECTING:
606 r = client_send_discover(client);
607 if (r < 0 && client->attempt >= 64)
612 case DHCP_STATE_INIT_REBOOT:
613 case DHCP_STATE_REQUESTING:
614 case DHCP_STATE_RENEWING:
615 case DHCP_STATE_REBINDING:
616 r = client_send_request(client);
617 if (r < 0 && client->attempt >= 64)
620 if (client->state == DHCP_STATE_INIT_REBOOT)
621 client->state = DHCP_STATE_REBOOTING;
623 client->request_sent = time_now;
627 case DHCP_STATE_REBOOTING:
628 case DHCP_STATE_BOUND:
632 case DHCP_STATE_STOPPED:
640 client_stop(client, r);
642 /* Errors were dealt with when stopping the client, don't spill
643 errors into the event loop handler */
647 static int client_initialize_events(sd_dhcp_client *client,
648 sd_event_io_handler_t io_callback) {
652 assert(client->event);
654 r = sd_event_add_io(client->event, &client->receive_message,
655 client->fd, EPOLLIN, io_callback,
660 r = sd_event_source_set_priority(client->receive_message,
661 client->event_priority);
665 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
667 r = sd_event_add_time(client->event,
668 &client->timeout_resend,
671 client_timeout_resend, client);
675 r = sd_event_source_set_priority(client->timeout_resend,
676 client->event_priority);
680 client_stop(client, r);
686 static int client_start(sd_dhcp_client *client) {
689 assert_return(client, -EINVAL);
690 assert_return(client->event, -EINVAL);
691 assert_return(client->index > 0, -EINVAL);
692 assert_return(client->fd < 0, -EBUSY);
693 assert_return(client->xid == 0, -EINVAL);
694 assert_return(client->state == DHCP_STATE_INIT ||
695 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
697 client->xid = random_u32();
699 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
701 client_stop(client, r);
706 if (client->state == DHCP_STATE_INIT) {
707 client->start_time = now(CLOCK_MONOTONIC);
711 return client_initialize_events(client, client_receive_message_raw);
714 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
716 sd_dhcp_client *client = userdata;
718 log_dhcp_client(client, "EXPIRED");
720 client = client_notify(client, DHCP_EVENT_EXPIRED);
722 /* lease was lost, start over if not freed or stopped in callback */
723 if (client && client->state != DHCP_STATE_STOPPED) {
724 client_initialize(client);
725 client_start(client);
731 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
732 sd_dhcp_client *client = userdata;
735 client->receive_message = sd_event_source_unref(client->receive_message);
736 client->fd = safe_close(client->fd);
738 client->state = DHCP_STATE_REBINDING;
741 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
743 client_stop(client, r);
748 return client_initialize_events(client, client_receive_message_raw);
751 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
753 sd_dhcp_client *client = userdata;
756 client->state = DHCP_STATE_RENEWING;
759 r = dhcp_network_bind_udp_socket(client->index,
760 client->lease->address,
763 client_stop(client, r);
769 return client_initialize_events(client, client_receive_message_udp);
772 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
774 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
777 r = dhcp_lease_new(&lease);
781 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
782 if (r != DHCP_OFFER) {
783 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
787 lease->next_server = offer->siaddr;
789 lease->address = offer->yiaddr;
791 if (lease->address == INADDR_ANY ||
792 lease->server_address == INADDR_ANY ||
793 lease->lifetime == 0) {
794 log_dhcp_client(client, "receieved lease lacks address, server "
795 "address or lease lifetime, ignoring");
799 if (lease->subnet_mask == INADDR_ANY) {
800 r = dhcp_lease_set_default_subnet_mask(lease);
802 log_dhcp_client(client, "receieved lease lacks subnet "
803 "mask, and a fallback one can not be "
804 "generated, ignoring");
809 sd_dhcp_lease_unref(client->lease);
810 client->lease = lease;
813 log_dhcp_client(client, "OFFER");
818 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
820 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
823 r = dhcp_lease_new(&lease);
827 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
829 log_dhcp_client(client, "NAK");
830 return DHCP_EVENT_NO_LEASE;
834 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
838 lease->next_server = ack->siaddr;
840 lease->address = ack->yiaddr;
842 if (lease->address == INADDR_ANY ||
843 lease->server_address == INADDR_ANY ||
844 lease->lifetime == 0) {
845 log_dhcp_client(client, "receieved lease lacks address, server "
846 "address or lease lifetime, ignoring");
850 if (lease->subnet_mask == INADDR_ANY) {
851 r = dhcp_lease_set_default_subnet_mask(lease);
853 log_dhcp_client(client, "receieved lease lacks subnet "
854 "mask, and a fallback one can not be "
855 "generated, ignoring");
860 r = DHCP_EVENT_IP_ACQUIRE;
862 if (client->lease->address != lease->address ||
863 client->lease->subnet_mask != lease->subnet_mask ||
864 client->lease->router != lease->router) {
865 r = DHCP_EVENT_IP_CHANGE;
868 client->lease = sd_dhcp_lease_unref(client->lease);
871 client->lease = lease;
874 log_dhcp_client(client, "ACK");
879 static uint64_t client_compute_timeout(sd_dhcp_client *client,
880 uint32_t lifetime, double factor) {
882 assert(client->request_sent);
885 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
886 + (random_u32() & 0x1fffff);
889 static int client_set_lease_timeouts(sd_dhcp_client *client) {
891 uint64_t lifetime_timeout;
894 char time_string[FORMAT_TIMESPAN_MAX];
898 assert(client->event);
899 assert(client->lease);
900 assert(client->lease->lifetime);
902 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
903 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
904 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
906 /* don't set timers for infinite leases */
907 if (client->lease->lifetime == 0xffffffff)
910 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
913 assert(client->request_sent <= time_now);
915 /* convert the various timeouts from relative (secs) to absolute (usecs) */
916 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
917 if (client->lease->t1 && client->lease->t2) {
918 /* both T1 and T2 are given */
919 if (client->lease->t1 < client->lease->t2 &&
920 client->lease->t2 < client->lease->lifetime) {
921 /* they are both valid */
922 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
923 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
926 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
927 client->lease->t2 = (client->lease->lifetime * 7) / 8;
928 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
929 client->lease->t1 = client->lease->lifetime / 2;
931 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
932 /* only T2 is given, and it is valid */
933 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
934 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
935 client->lease->t1 = client->lease->lifetime / 2;
936 if (t2_timeout <= t1_timeout) {
937 /* the computed T1 would be invalid, so discard T2 */
938 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
939 client->lease->t2 = (client->lease->lifetime * 7) / 8;
941 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
942 /* only T1 is given, and it is valid */
943 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
944 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
945 client->lease->t2 = (client->lease->lifetime * 7) / 8;
946 if (t2_timeout <= t1_timeout) {
947 /* the computed T2 would be invalid, so discard T1 */
948 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
949 client->lease->t2 = client->lease->lifetime / 2;
952 /* fall back to the default timeouts */
953 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
954 client->lease->t1 = client->lease->lifetime / 2;
955 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
956 client->lease->t2 = (client->lease->lifetime * 7) / 8;
959 /* arm lifetime timeout */
960 r = sd_event_add_time(client->event, &client->timeout_expire,
962 lifetime_timeout, 10 * USEC_PER_MSEC,
963 client_timeout_expire, client);
967 r = sd_event_source_set_priority(client->timeout_expire,
968 client->event_priority);
972 log_dhcp_client(client, "lease expires in %s",
973 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
974 lifetime_timeout - time_now, 0));
976 /* don't arm earlier timeouts if this has already expired */
977 if (lifetime_timeout <= time_now)
981 r = sd_event_add_time(client->event,
986 client_timeout_t2, client);
990 r = sd_event_source_set_priority(client->timeout_t2,
991 client->event_priority);
995 log_dhcp_client(client, "T2 expires in %s",
996 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
997 t2_timeout - time_now, 0));
999 /* don't arm earlier timeout if this has already expired */
1000 if (t2_timeout <= time_now)
1003 /* arm T1 timeout */
1004 r = sd_event_add_time(client->event,
1005 &client->timeout_t1,
1007 t1_timeout, 10 * USEC_PER_MSEC,
1008 client_timeout_t1, client);
1012 r = sd_event_source_set_priority(client->timeout_t1,
1013 client->event_priority);
1017 log_dhcp_client(client, "T1 expires in %s",
1018 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1019 t1_timeout - time_now, 0));
1024 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1026 int r = 0, notify_event = 0;
1029 assert(client->event);
1032 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1033 log_dhcp_client(client, "not a DHCP message: ignoring");
1037 if (message->op != BOOTREPLY) {
1038 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1042 if (be32toh(message->xid) != client->xid) {
1043 log_dhcp_client(client, "received xid (%u) does not match "
1044 "expected (%u): ignoring",
1045 be32toh(message->xid), client->xid);
1049 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1050 log_dhcp_client(client, "not an ethernet packet");
1054 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1056 log_dhcp_client(client, "received chaddr does not match "
1057 "expected: ignoring");
1061 switch (client->state) {
1062 case DHCP_STATE_SELECTING:
1064 r = client_handle_offer(client, message, len);
1067 client->timeout_resend =
1068 sd_event_source_unref(client->timeout_resend);
1070 client->state = DHCP_STATE_REQUESTING;
1071 client->attempt = 1;
1073 r = sd_event_add_time(client->event,
1074 &client->timeout_resend,
1077 client_timeout_resend, client);
1081 r = sd_event_source_set_priority(client->timeout_resend,
1082 client->event_priority);
1085 } else if (r == -ENOMSG)
1086 /* invalid message, let's ignore it */
1091 case DHCP_STATE_REBOOTING:
1092 case DHCP_STATE_REQUESTING:
1093 case DHCP_STATE_RENEWING:
1094 case DHCP_STATE_REBINDING:
1096 r = client_handle_ack(client, message, len);
1097 if (r == DHCP_EVENT_NO_LEASE) {
1099 client->timeout_resend =
1100 sd_event_source_unref(client->timeout_resend);
1102 if (client->state == DHCP_STATE_REBOOTING) {
1103 r = client_initialize(client);
1107 r = client_start(client);
1111 log_dhcp_client(client, "REBOOTED");
1115 } else if (r >= 0) {
1116 client->timeout_resend =
1117 sd_event_source_unref(client->timeout_resend);
1119 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1120 DHCP_STATE_REBOOTING))
1121 notify_event = DHCP_EVENT_IP_ACQUIRE;
1122 else if (r != DHCP_EVENT_IP_ACQUIRE)
1125 client->state = DHCP_STATE_BOUND;
1126 client->attempt = 1;
1128 client->last_addr = client->lease->address;
1130 r = client_set_lease_timeouts(client);
1135 client = client_notify(client, notify_event);
1137 client->state == DHCP_STATE_STOPPED)
1141 client->receive_message =
1142 sd_event_source_unref(client->receive_message);
1143 client->fd = safe_close(client->fd);
1144 } else if (r == -ENOMSG)
1145 /* invalid message, let's ignore it */
1150 case DHCP_STATE_INIT:
1151 case DHCP_STATE_INIT_REBOOT:
1152 case DHCP_STATE_BOUND:
1156 case DHCP_STATE_STOPPED:
1162 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1163 client_stop(client, r);
1168 static int client_receive_message_udp(sd_event_source *s, int fd,
1169 uint32_t revents, void *userdata) {
1170 sd_dhcp_client *client = userdata;
1171 _cleanup_free_ DHCPMessage *message = NULL;
1172 int buflen = 0, len, r;
1177 r = ioctl(fd, FIONREAD, &buflen);
1178 if (r < 0 || buflen <= 0)
1179 buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE;
1181 message = malloc0(buflen);
1185 len = read(fd, message, buflen);
1187 log_dhcp_client(client, "could not receive message from UDP "
1188 "socket: %s", strerror(errno));
1190 } else if ((size_t)len < sizeof(DHCPMessage))
1193 return client_handle_message(client, message, len);
1196 static int client_receive_message_raw(sd_event_source *s, int fd,
1197 uint32_t revents, void *userdata) {
1198 sd_dhcp_client *client = userdata;
1199 _cleanup_free_ DHCPPacket *packet = NULL;
1200 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1201 struct iovec iov = {};
1202 struct msghdr msg = {
1205 .msg_control = cmsgbuf,
1206 .msg_controllen = sizeof(cmsgbuf),
1208 struct cmsghdr *cmsg;
1209 bool checksum = true;
1210 int buflen = 0, len, r;
1215 r = ioctl(fd, FIONREAD, &buflen);
1216 if (r < 0 || buflen <= 0)
1217 buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE;
1219 packet = malloc0(buflen);
1223 iov.iov_base = packet;
1224 iov.iov_len = buflen;
1226 len = recvmsg(fd, &msg, 0);
1228 log_dhcp_client(client, "could not receive message from raw "
1229 "socket: %s", strerror(errno));
1231 } else if ((size_t)len < sizeof(DHCPPacket))
1234 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1235 if (cmsg->cmsg_level == SOL_PACKET &&
1236 cmsg->cmsg_type == PACKET_AUXDATA &&
1237 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1238 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1240 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1245 r = dhcp_packet_verify_headers(packet, len, checksum);
1249 len -= DHCP_IP_UDP_SIZE;
1251 return client_handle_message(client, &packet->dhcp, len);
1254 int sd_dhcp_client_start(sd_dhcp_client *client) {
1257 assert_return(client, -EINVAL);
1259 r = client_initialize(client);
1263 if (client->last_addr)
1264 client->state = DHCP_STATE_INIT_REBOOT;
1266 r = client_start(client);
1268 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1270 ether_ntoa(&client->client_id.mac_addr));
1275 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1276 assert_return(client, -EINVAL);
1278 if (client_stop(client, DHCP_EVENT_STOP))
1279 client->state = DHCP_STATE_STOPPED;
1284 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1288 assert_return(client, -EINVAL);
1289 assert_return(!client->event, -EBUSY);
1292 client->event = sd_event_ref(event);
1294 r = sd_event_default(&client->event);
1299 client->event_priority = priority;
1304 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1305 assert_return(client, -EINVAL);
1307 client->event = sd_event_unref(client->event);
1312 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1316 return client->event;
1319 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1321 assert_se(REFCNT_INC(client->n_ref) >= 2);
1326 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1327 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1328 log_dhcp_client(client, "UNREF");
1330 client_initialize(client);
1332 client->receive_message =
1333 sd_event_source_unref(client->receive_message);
1335 sd_dhcp_client_detach_event(client);
1337 sd_dhcp_lease_unref(client->lease);
1339 free(client->req_opts);
1348 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
1349 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1351 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1352 _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1354 assert_return(ret, -EINVAL);
1356 client = new0(sd_dhcp_client, 1);
1360 client->n_ref = REFCNT_INIT;
1361 client->state = DHCP_STATE_INIT;
1364 client->attempt = 1;
1366 client->req_opts_size = ELEMENTSOF(default_req_opts);
1368 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1369 if (!client->req_opts)