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 sd_dhcp_client *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 bool need_restart = false;
158 assert_return(client, -EINVAL);
159 assert_return(addr, -EINVAL);
161 if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
164 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
165 log_dhcp_client(client, "Changing MAC address on running DHCP "
166 "client, restarting");
168 client = client_stop(client, DHCP_EVENT_STOP);
174 memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
175 client->client_id.type = 0x01;
177 if (need_restart && client->state != DHCP_STATE_STOPPED)
178 sd_dhcp_client_start(client);
183 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
184 assert_return(client, -EINVAL);
185 assert_return(ret, -EINVAL);
187 if (client->state != DHCP_STATE_BOUND &&
188 client->state != DHCP_STATE_RENEWING &&
189 client->state != DHCP_STATE_REBINDING)
190 return -EADDRNOTAVAIL;
192 *ret = sd_dhcp_lease_ref(client->lease);
197 static sd_dhcp_client *client_notify(sd_dhcp_client *client, int event) {
199 client = sd_dhcp_client_ref(client);
200 client->cb(client, event, client->userdata);
201 client = sd_dhcp_client_unref(client);
207 static int client_initialize(sd_dhcp_client *client) {
208 assert_return(client, -EINVAL);
210 client->receive_message =
211 sd_event_source_unref(client->receive_message);
213 client->fd = asynchronous_close(client->fd);
215 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
217 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
218 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
219 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
223 client->state = DHCP_STATE_INIT;
227 client->lease = sd_dhcp_lease_unref(client->lease);
232 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error) {
233 assert_return(client, NULL);
236 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
239 case DHCP_EVENT_STOP:
240 log_dhcp_client(client, "STOPPED");
242 case DHCP_EVENT_NO_LEASE:
243 log_dhcp_client(client, "STOPPED: No lease");
246 log_dhcp_client(client, "STOPPED: Unknown reason");
251 client = client_notify(client, error);
254 client_initialize(client);
259 static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
260 uint8_t type, uint8_t **opt, size_t *optlen) {
265 assert(client->secs);
269 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
271 r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt,
276 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
277 refuse to issue an DHCP lease if 'secs' is set to zero */
278 message->secs = htobe16(client->secs);
280 /* RFC2132 section 4.1.1:
281 The client MUST include its hardware address in the ’chaddr’ field, if
282 necessary for delivery of DHCP reply messages.
284 memcpy(&message->chaddr, &client->client_id.mac_addr, ETH_ALEN);
286 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
287 Identifier option is not set */
288 r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
289 sizeof(client->client_id), &client->client_id);
294 /* RFC2131 section 3.5:
295 in its initial DHCPDISCOVER or DHCPREQUEST message, a
296 client may provide the server with a list of specific
297 parameters the client is interested in. If the client
298 includes a list of parameters in a DHCPDISCOVER message,
299 it MUST include that list in any subsequent DHCPREQUEST
302 r = dhcp_option_append(opt, optlen,
303 DHCP_OPTION_PARAMETER_REQUEST_LIST,
304 client->req_opts_size,
309 /* RFC2131 section 3.5:
310 The client SHOULD include the ’maximum DHCP message size’ option to
311 let the server know how large the server may make its DHCP messages.
313 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
314 than the defined default size unless the Maximum Messge Size option
317 max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
318 DHCP_MIN_OPTIONS_SIZE);
319 r = dhcp_option_append(opt, optlen,
320 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
328 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
330 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
331 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
333 return dhcp_network_send_raw_socket(client->fd, &client->link,
337 static int client_send_discover(sd_dhcp_client *client) {
338 _cleanup_free_ DHCPPacket *discover = NULL;
345 assert(client->state == DHCP_STATE_INIT ||
346 client->state == DHCP_STATE_SELECTING);
348 /* See RFC2131 section 4.4.1 */
350 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
353 assert(time_now >= client->start_time);
355 /* seconds between sending first and last DISCOVER
356 * must always be strictly positive to deal with broken servers */
357 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
359 optlen = DHCP_MIN_OPTIONS_SIZE;
360 len = sizeof(DHCPPacket) + optlen;
362 discover = malloc0(len);
366 r = client_message_init(client, &discover->dhcp, DHCP_DISCOVER,
371 /* the client may suggest values for the network address
372 and lease time in the DHCPDISCOVER message. The client may include
373 the ’requested IP address’ option to suggest that a particular IP
374 address be assigned, and may include the ’IP address lease time’
375 option to suggest the lease time it would like.
377 if (client->last_addr != INADDR_ANY) {
378 r = dhcp_option_append(&opt, &optlen,
379 DHCP_OPTION_REQUESTED_IP_ADDRESS,
380 4, &client->last_addr);
385 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
389 /* We currently ignore:
390 The client SHOULD wait a random time between one and ten seconds to
391 desynchronize the use of DHCP at startup.
393 r = dhcp_client_send_raw(client, discover, len - optlen);
397 log_dhcp_client(client, "DISCOVER");
402 static int client_send_request(sd_dhcp_client *client) {
403 _cleanup_free_ DHCPPacket *request;
408 optlen = DHCP_MIN_OPTIONS_SIZE;
409 len = sizeof(DHCPPacket) + optlen;
411 request = malloc0(len);
415 r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt,
420 switch (client->state) {
421 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
422 SELECTING should be REQUESTING)
425 case DHCP_STATE_REQUESTING:
426 /* Client inserts the address of the selected server in ’server
427 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
428 filled in with the yiaddr value from the chosen DHCPOFFER.
431 r = dhcp_option_append(&opt, &optlen,
432 DHCP_OPTION_SERVER_IDENTIFIER,
433 4, &client->lease->server_address);
437 r = dhcp_option_append(&opt, &optlen,
438 DHCP_OPTION_REQUESTED_IP_ADDRESS,
439 4, &client->lease->address);
445 case DHCP_STATE_INIT_REBOOT:
446 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
447 option MUST be filled in with client’s notion of its previously
448 assigned address. ’ciaddr’ MUST be zero.
450 r = dhcp_option_append(&opt, &optlen,
451 DHCP_OPTION_REQUESTED_IP_ADDRESS,
452 4, &client->last_addr);
457 case DHCP_STATE_RENEWING:
458 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
459 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
460 client’s IP address.
464 case DHCP_STATE_REBINDING:
465 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
466 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
467 client’s IP address.
469 This message MUST be broadcast to the 0xffffffff IP broadcast address.
471 request->dhcp.ciaddr = client->lease->address;
475 case DHCP_STATE_INIT:
476 case DHCP_STATE_SELECTING:
477 case DHCP_STATE_REBOOTING:
478 case DHCP_STATE_BOUND:
479 case DHCP_STATE_STOPPED:
483 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
487 if (client->state == DHCP_STATE_RENEWING) {
488 r = dhcp_network_send_udp_socket(client->fd,
489 client->lease->server_address,
492 len - optlen - DHCP_IP_UDP_SIZE);
494 r = dhcp_client_send_raw(client, request, len - optlen);
499 switch (client->state) {
500 case DHCP_STATE_REQUESTING:
501 log_dhcp_client(client, "REQUEST (requesting)");
503 case DHCP_STATE_INIT_REBOOT:
504 log_dhcp_client(client, "REQUEST (init-reboot)");
506 case DHCP_STATE_RENEWING:
507 log_dhcp_client(client, "REQUEST (renewing)");
509 case DHCP_STATE_REBINDING:
510 log_dhcp_client(client, "REQUEST (rebinding)");
513 log_dhcp_client(client, "REQUEST (invalid)");
520 static int client_start(sd_dhcp_client *client);
522 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
524 sd_dhcp_client *client = userdata;
525 usec_t next_timeout = 0;
532 assert(client->event);
534 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
538 switch (client->state) {
539 case DHCP_STATE_RENEWING:
541 time_left = (client->lease->t2 - client->lease->t1) / 2;
545 next_timeout = time_now + time_left * USEC_PER_SEC;
549 case DHCP_STATE_REBINDING:
551 time_left = (client->lease->lifetime - client->lease->t2) / 2;
555 next_timeout = time_now + time_left * USEC_PER_SEC;
558 case DHCP_STATE_REBOOTING:
559 /* start over as we did not receive a timely ack or nak */
560 r = client_initialize(client);
564 r = client_start(client);
568 log_dhcp_client(client, "REBOOTED");
572 case DHCP_STATE_INIT:
573 case DHCP_STATE_INIT_REBOOT:
574 case DHCP_STATE_SELECTING:
575 case DHCP_STATE_REQUESTING:
576 case DHCP_STATE_BOUND:
578 if (client->attempt < 64)
579 client->attempt *= 2;
581 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
585 case DHCP_STATE_STOPPED:
590 next_timeout += (random_u32() & 0x1fffff);
592 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
594 r = sd_event_add_time(client->event,
595 &client->timeout_resend,
597 next_timeout, 10 * USEC_PER_MSEC,
598 client_timeout_resend, client);
602 r = sd_event_source_set_priority(client->timeout_resend,
603 client->event_priority);
607 switch (client->state) {
608 case DHCP_STATE_INIT:
609 r = client_send_discover(client);
611 client->state = DHCP_STATE_SELECTING;
614 if (client->attempt >= 64)
620 case DHCP_STATE_SELECTING:
621 r = client_send_discover(client);
622 if (r < 0 && client->attempt >= 64)
627 case DHCP_STATE_INIT_REBOOT:
628 case DHCP_STATE_REQUESTING:
629 case DHCP_STATE_RENEWING:
630 case DHCP_STATE_REBINDING:
631 r = client_send_request(client);
632 if (r < 0 && client->attempt >= 64)
635 if (client->state == DHCP_STATE_INIT_REBOOT)
636 client->state = DHCP_STATE_REBOOTING;
638 client->request_sent = time_now;
642 case DHCP_STATE_REBOOTING:
643 case DHCP_STATE_BOUND:
647 case DHCP_STATE_STOPPED:
655 client_stop(client, r);
657 /* Errors were dealt with when stopping the client, don't spill
658 errors into the event loop handler */
662 static int client_initialize_events(sd_dhcp_client *client,
663 sd_event_io_handler_t io_callback) {
667 assert(client->event);
669 r = sd_event_add_io(client->event, &client->receive_message,
670 client->fd, EPOLLIN, io_callback,
675 r = sd_event_source_set_priority(client->receive_message,
676 client->event_priority);
680 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
682 r = sd_event_add_time(client->event,
683 &client->timeout_resend,
686 client_timeout_resend, client);
690 r = sd_event_source_set_priority(client->timeout_resend,
691 client->event_priority);
695 client_stop(client, r);
701 static int client_start(sd_dhcp_client *client) {
704 assert_return(client, -EINVAL);
705 assert_return(client->event, -EINVAL);
706 assert_return(client->index > 0, -EINVAL);
707 assert_return(client->fd < 0, -EBUSY);
708 assert_return(client->xid == 0, -EINVAL);
709 assert_return(client->state == DHCP_STATE_INIT ||
710 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
712 client->xid = random_u32();
714 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
716 client_stop(client, r);
721 if (client->state == DHCP_STATE_INIT) {
722 client->start_time = now(CLOCK_MONOTONIC);
726 return client_initialize_events(client, client_receive_message_raw);
729 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
731 sd_dhcp_client *client = userdata;
733 log_dhcp_client(client, "EXPIRED");
735 client = client_notify(client, DHCP_EVENT_EXPIRED);
737 /* lease was lost, start over if not freed or stopped in callback */
738 if (client && 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;
750 client->receive_message = sd_event_source_unref(client->receive_message);
751 client->fd = asynchronous_close(client->fd);
753 client->state = DHCP_STATE_REBINDING;
756 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
758 client_stop(client, r);
763 return client_initialize_events(client, client_receive_message_raw);
766 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
768 sd_dhcp_client *client = userdata;
771 client->state = DHCP_STATE_RENEWING;
774 r = dhcp_network_bind_udp_socket(client->lease->address,
777 client_stop(client, r);
783 return client_initialize_events(client, client_receive_message_udp);
786 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
788 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
791 r = dhcp_lease_new(&lease);
795 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
796 if (r != DHCP_OFFER) {
797 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
801 lease->next_server = offer->siaddr;
803 lease->address = offer->yiaddr;
805 if (lease->address == INADDR_ANY ||
806 lease->server_address == INADDR_ANY ||
807 lease->lifetime == 0) {
808 log_dhcp_client(client, "receieved lease lacks address, server "
809 "address or lease lifetime, ignoring");
813 if (lease->subnet_mask == INADDR_ANY) {
814 r = dhcp_lease_set_default_subnet_mask(lease);
816 log_dhcp_client(client, "receieved lease lacks subnet "
817 "mask, and a fallback one can not be "
818 "generated, ignoring");
823 sd_dhcp_lease_unref(client->lease);
824 client->lease = lease;
827 log_dhcp_client(client, "OFFER");
832 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
834 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
837 r = dhcp_lease_new(&lease);
841 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
843 log_dhcp_client(client, "NAK");
844 return DHCP_EVENT_NO_LEASE;
848 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
852 lease->next_server = ack->siaddr;
854 lease->address = ack->yiaddr;
856 if (lease->address == INADDR_ANY ||
857 lease->server_address == INADDR_ANY ||
858 lease->lifetime == 0) {
859 log_dhcp_client(client, "receieved lease lacks address, server "
860 "address or lease lifetime, ignoring");
864 if (lease->subnet_mask == INADDR_ANY) {
865 r = dhcp_lease_set_default_subnet_mask(lease);
867 log_dhcp_client(client, "receieved lease lacks subnet "
868 "mask, and a fallback one can not be "
869 "generated, ignoring");
874 r = DHCP_EVENT_IP_ACQUIRE;
876 if (client->lease->address != lease->address ||
877 client->lease->subnet_mask != lease->subnet_mask ||
878 client->lease->router != lease->router) {
879 r = DHCP_EVENT_IP_CHANGE;
882 client->lease = sd_dhcp_lease_unref(client->lease);
885 client->lease = lease;
888 log_dhcp_client(client, "ACK");
893 static uint64_t client_compute_timeout(sd_dhcp_client *client,
894 uint32_t lifetime, double factor) {
896 assert(client->request_sent);
899 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
900 + (random_u32() & 0x1fffff);
903 static int client_set_lease_timeouts(sd_dhcp_client *client) {
905 uint64_t lifetime_timeout;
908 char time_string[FORMAT_TIMESPAN_MAX];
912 assert(client->event);
913 assert(client->lease);
914 assert(client->lease->lifetime);
916 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
917 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
918 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
920 /* don't set timers for infinite leases */
921 if (client->lease->lifetime == 0xffffffff)
924 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
927 assert(client->request_sent <= time_now);
929 /* convert the various timeouts from relative (secs) to absolute (usecs) */
930 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
931 if (client->lease->t1 && client->lease->t2) {
932 /* both T1 and T2 are given */
933 if (client->lease->t1 < client->lease->t2 &&
934 client->lease->t2 < client->lease->lifetime) {
935 /* they are both valid */
936 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
937 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
940 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
941 client->lease->t2 = (client->lease->lifetime * 7) / 8;
942 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
943 client->lease->t1 = client->lease->lifetime / 2;
945 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
946 /* only T2 is given, and it is valid */
947 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
948 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
949 client->lease->t1 = client->lease->lifetime / 2;
950 if (t2_timeout <= t1_timeout) {
951 /* the computed T1 would be invalid, so discard T2 */
952 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
953 client->lease->t2 = (client->lease->lifetime * 7) / 8;
955 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
956 /* only T1 is given, and it is valid */
957 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
958 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
959 client->lease->t2 = (client->lease->lifetime * 7) / 8;
960 if (t2_timeout <= t1_timeout) {
961 /* the computed T2 would be invalid, so discard T1 */
962 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
963 client->lease->t2 = client->lease->lifetime / 2;
966 /* fall back to the default timeouts */
967 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
968 client->lease->t1 = client->lease->lifetime / 2;
969 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
970 client->lease->t2 = (client->lease->lifetime * 7) / 8;
973 /* arm lifetime timeout */
974 r = sd_event_add_time(client->event, &client->timeout_expire,
976 lifetime_timeout, 10 * USEC_PER_MSEC,
977 client_timeout_expire, client);
981 r = sd_event_source_set_priority(client->timeout_expire,
982 client->event_priority);
986 log_dhcp_client(client, "lease expires in %s",
987 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
988 lifetime_timeout - time_now, 0));
990 /* don't arm earlier timeouts if this has already expired */
991 if (lifetime_timeout <= time_now)
995 r = sd_event_add_time(client->event,
1000 client_timeout_t2, client);
1004 r = sd_event_source_set_priority(client->timeout_t2,
1005 client->event_priority);
1009 log_dhcp_client(client, "T2 expires in %s",
1010 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1011 t2_timeout - time_now, 0));
1013 /* don't arm earlier timeout if this has already expired */
1014 if (t2_timeout <= time_now)
1017 /* arm T1 timeout */
1018 r = sd_event_add_time(client->event,
1019 &client->timeout_t1,
1021 t1_timeout, 10 * USEC_PER_MSEC,
1022 client_timeout_t1, client);
1026 r = sd_event_source_set_priority(client->timeout_t1,
1027 client->event_priority);
1031 log_dhcp_client(client, "T1 expires in %s",
1032 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1033 t1_timeout - time_now, 0));
1038 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1040 int r = 0, notify_event = 0;
1043 assert(client->event);
1046 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1047 log_dhcp_client(client, "not a DHCP message: ignoring");
1051 if (message->op != BOOTREPLY) {
1052 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1056 if (be32toh(message->xid) != client->xid) {
1057 log_dhcp_client(client, "received xid (%u) does not match "
1058 "expected (%u): ignoring",
1059 be32toh(message->xid), client->xid);
1063 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1064 log_dhcp_client(client, "not an ethernet packet");
1068 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1070 log_dhcp_client(client, "received chaddr does not match "
1071 "expected: ignoring");
1075 switch (client->state) {
1076 case DHCP_STATE_SELECTING:
1078 r = client_handle_offer(client, message, len);
1081 client->timeout_resend =
1082 sd_event_source_unref(client->timeout_resend);
1084 client->state = DHCP_STATE_REQUESTING;
1085 client->attempt = 1;
1087 r = sd_event_add_time(client->event,
1088 &client->timeout_resend,
1091 client_timeout_resend, client);
1095 r = sd_event_source_set_priority(client->timeout_resend,
1096 client->event_priority);
1099 } else if (r == -ENOMSG)
1100 /* invalid message, let's ignore it */
1105 case DHCP_STATE_REBOOTING:
1106 case DHCP_STATE_REQUESTING:
1107 case DHCP_STATE_RENEWING:
1108 case DHCP_STATE_REBINDING:
1110 r = client_handle_ack(client, message, len);
1111 if (r == DHCP_EVENT_NO_LEASE) {
1113 client->timeout_resend =
1114 sd_event_source_unref(client->timeout_resend);
1116 if (client->state == DHCP_STATE_REBOOTING) {
1117 r = client_initialize(client);
1121 r = client_start(client);
1125 log_dhcp_client(client, "REBOOTED");
1129 } else if (r >= 0) {
1130 client->timeout_resend =
1131 sd_event_source_unref(client->timeout_resend);
1133 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1134 DHCP_STATE_REBOOTING))
1135 notify_event = DHCP_EVENT_IP_ACQUIRE;
1136 else if (r != DHCP_EVENT_IP_ACQUIRE)
1139 client->state = DHCP_STATE_BOUND;
1140 client->attempt = 1;
1142 client->last_addr = client->lease->address;
1144 r = client_set_lease_timeouts(client);
1149 client = client_notify(client, notify_event);
1151 client->state == DHCP_STATE_STOPPED)
1155 client->receive_message =
1156 sd_event_source_unref(client->receive_message);
1157 client->fd = asynchronous_close(client->fd);
1158 } else if (r == -ENOMSG)
1159 /* invalid message, let's ignore it */
1164 case DHCP_STATE_INIT:
1165 case DHCP_STATE_INIT_REBOOT:
1166 case DHCP_STATE_BOUND:
1170 case DHCP_STATE_STOPPED:
1176 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1177 client_stop(client, r);
1182 static int client_receive_message_udp(sd_event_source *s, int fd,
1183 uint32_t revents, void *userdata) {
1184 sd_dhcp_client *client = userdata;
1185 _cleanup_free_ DHCPMessage *message = NULL;
1186 int buflen = 0, len, r;
1191 r = ioctl(fd, FIONREAD, &buflen);
1192 if (r < 0 || buflen <= 0)
1193 buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE;
1195 message = malloc0(buflen);
1199 len = read(fd, message, buflen);
1201 log_dhcp_client(client, "could not receive message from UDP "
1202 "socket: %s", strerror(errno));
1204 } else if ((size_t)len < sizeof(DHCPMessage))
1207 return client_handle_message(client, message, len);
1210 static int client_receive_message_raw(sd_event_source *s, int fd,
1211 uint32_t revents, void *userdata) {
1212 sd_dhcp_client *client = userdata;
1213 _cleanup_free_ DHCPPacket *packet = NULL;
1214 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1215 struct iovec iov = {};
1216 struct msghdr msg = {
1219 .msg_control = cmsgbuf,
1220 .msg_controllen = sizeof(cmsgbuf),
1222 struct cmsghdr *cmsg;
1223 bool checksum = true;
1224 int buflen = 0, len, r;
1229 r = ioctl(fd, FIONREAD, &buflen);
1230 if (r < 0 || buflen <= 0)
1231 buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE;
1233 packet = malloc0(buflen);
1237 iov.iov_base = packet;
1238 iov.iov_len = buflen;
1240 len = recvmsg(fd, &msg, 0);
1242 log_dhcp_client(client, "could not receive message from raw "
1243 "socket: %s", strerror(errno));
1245 } else if ((size_t)len < sizeof(DHCPPacket))
1248 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1249 if (cmsg->cmsg_level == SOL_PACKET &&
1250 cmsg->cmsg_type == PACKET_AUXDATA &&
1251 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1252 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1254 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1259 r = dhcp_packet_verify_headers(packet, len, checksum);
1263 len -= DHCP_IP_UDP_SIZE;
1265 return client_handle_message(client, &packet->dhcp, len);
1268 int sd_dhcp_client_start(sd_dhcp_client *client) {
1271 assert_return(client, -EINVAL);
1273 r = client_initialize(client);
1277 if (client->last_addr)
1278 client->state = DHCP_STATE_INIT_REBOOT;
1280 r = client_start(client);
1282 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1284 ether_ntoa(&client->client_id.mac_addr));
1289 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1290 assert_return(client, -EINVAL);
1292 if (client_stop(client, DHCP_EVENT_STOP))
1293 client->state = DHCP_STATE_STOPPED;
1298 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1302 assert_return(client, -EINVAL);
1303 assert_return(!client->event, -EBUSY);
1306 client->event = sd_event_ref(event);
1308 r = sd_event_default(&client->event);
1313 client->event_priority = priority;
1318 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1319 assert_return(client, -EINVAL);
1321 client->event = sd_event_unref(client->event);
1326 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1330 return client->event;
1333 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1335 assert_se(REFCNT_INC(client->n_ref) >= 2);
1340 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1341 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1342 log_dhcp_client(client, "UNREF");
1344 client_initialize(client);
1346 client->receive_message =
1347 sd_event_source_unref(client->receive_message);
1349 sd_dhcp_client_detach_event(client);
1351 sd_dhcp_lease_unref(client->lease);
1353 free(client->req_opts);
1362 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
1363 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1365 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1366 _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1368 assert_return(ret, -EINVAL);
1370 client = new0(sd_dhcp_client, 1);
1374 client->n_ref = REFCNT_INIT;
1375 client->state = DHCP_STATE_INIT;
1378 client->attempt = 1;
1380 client->req_opts_size = ELEMENTSOF(default_req_opts);
1382 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1383 if (!client->req_opts)