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;
65 sd_event_source *timeout_t1;
66 sd_event_source *timeout_t2;
67 sd_event_source *timeout_expire;
68 sd_dhcp_client_cb_t cb;
73 static const uint8_t default_req_opts[] = {
74 DHCP_OPTION_SUBNET_MASK,
76 DHCP_OPTION_HOST_NAME,
77 DHCP_OPTION_DOMAIN_NAME,
78 DHCP_OPTION_DOMAIN_NAME_SERVER,
79 DHCP_OPTION_NTP_SERVER,
82 static int client_receive_message_raw(sd_event_source *s, int fd,
83 uint32_t revents, void *userdata);
84 static int client_receive_message_udp(sd_event_source *s, int fd,
85 uint32_t revents, void *userdata);
86 static void client_stop(sd_dhcp_client *client, int error);
88 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
90 assert_return(client, -EINVAL);
93 client->userdata = userdata;
98 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
101 assert_return(client, -EINVAL);
102 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
103 DHCP_STATE_STOPPED), -EBUSY);
106 case DHCP_OPTION_PAD:
107 case DHCP_OPTION_OVERLOAD:
108 case DHCP_OPTION_MESSAGE_TYPE:
109 case DHCP_OPTION_PARAMETER_REQUEST_LIST:
110 case DHCP_OPTION_END:
117 for (i = 0; i < client->req_opts_size; i++)
118 if (client->req_opts[i] == option)
121 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
122 client->req_opts_size + 1))
125 client->req_opts[client->req_opts_size++] = option;
130 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
131 const struct in_addr *last_addr) {
132 assert_return(client, -EINVAL);
133 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
134 DHCP_STATE_STOPPED), -EBUSY);
137 client->last_addr = last_addr->s_addr;
139 client->last_addr = INADDR_ANY;
144 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
145 assert_return(client, -EINVAL);
146 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
147 DHCP_STATE_STOPPED), -EBUSY);
148 assert_return(interface_index > 0, -EINVAL);
150 client->index = interface_index;
155 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
156 const struct ether_addr *addr) {
157 DHCP_CLIENT_DONT_DESTROY(client);
158 bool need_restart = false;
160 assert_return(client, -EINVAL);
161 assert_return(addr, -EINVAL);
163 if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
166 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
167 log_dhcp_client(client, "Changing MAC address on running DHCP "
168 "client, restarting");
170 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_set_hostname(sd_dhcp_client *client,
183 const char *hostname) {
184 char *new_hostname = NULL;
186 assert_return(client, -EINVAL);
188 if (streq_ptr(client->hostname, hostname))
192 new_hostname = strdup(hostname);
197 free(client->hostname);
198 client->hostname = new_hostname;
203 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
204 assert_return(client, -EINVAL);
205 assert_return(ret, -EINVAL);
207 if (client->state != DHCP_STATE_BOUND &&
208 client->state != DHCP_STATE_RENEWING &&
209 client->state != DHCP_STATE_REBINDING)
210 return -EADDRNOTAVAIL;
212 *ret = sd_dhcp_lease_ref(client->lease);
217 static void client_notify(sd_dhcp_client *client, int event) {
219 client->cb(client, event, client->userdata);
222 static int client_initialize(sd_dhcp_client *client) {
223 assert_return(client, -EINVAL);
225 client->receive_message =
226 sd_event_source_unref(client->receive_message);
228 client->fd = asynchronous_close(client->fd);
230 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
232 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
233 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
234 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
238 client->state = DHCP_STATE_INIT;
242 client->lease = sd_dhcp_lease_unref(client->lease);
247 static void client_stop(sd_dhcp_client *client, int error) {
251 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
254 case DHCP_EVENT_STOP:
255 log_dhcp_client(client, "STOPPED");
257 case DHCP_EVENT_NO_LEASE:
258 log_dhcp_client(client, "STOPPED: No lease");
261 log_dhcp_client(client, "STOPPED: Unknown reason");
266 client_notify(client, error);
268 client_initialize(client);
271 static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
272 uint8_t type, size_t *_optlen, size_t *_optoffset) {
273 _cleanup_free_ DHCPPacket *packet;
274 size_t optlen, optoffset, size;
279 assert(client->secs);
283 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
285 optlen = DHCP_MIN_OPTIONS_SIZE;
286 size = sizeof(DHCPPacket) + optlen;
288 packet = malloc0(size);
292 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
297 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
298 refuse to issue an DHCP lease if 'secs' is set to zero */
299 packet->dhcp.secs = htobe16(client->secs);
301 /* RFC2132 section 4.1
302 A client that cannot receive unicast IP datagrams until its protocol
303 software has been configured with an IP address SHOULD set the
304 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
305 DHCPREQUEST messages that client sends. The BROADCAST bit will
306 provide a hint to the DHCP server and BOOTP relay agent to broadcast
307 any messages to the client on the client's subnet. */
308 packet->dhcp.flags = htobe16(0x8000);
310 /* RFC2132 section 4.1.1:
311 The client MUST include its hardware address in the ’chaddr’ field, if
312 necessary for delivery of DHCP reply messages.
314 memcpy(&packet->dhcp.chaddr, &client->client_id.mac_addr, ETH_ALEN);
316 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
317 Identifier option is not set */
318 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
319 DHCP_OPTION_CLIENT_IDENTIFIER,
320 sizeof(client->client_id), &client->client_id);
325 /* RFC2131 section 3.5:
326 in its initial DHCPDISCOVER or DHCPREQUEST message, a
327 client may provide the server with a list of specific
328 parameters the client is interested in. If the client
329 includes a list of parameters in a DHCPDISCOVER message,
330 it MUST include that list in any subsequent DHCPREQUEST
333 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
334 DHCP_OPTION_PARAMETER_REQUEST_LIST,
335 client->req_opts_size, client->req_opts);
339 /* RFC2131 section 3.5:
340 The client SHOULD include the ’maximum DHCP message size’ option to
341 let the server know how large the server may make its DHCP messages.
343 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
344 than the defined default size unless the Maximum Messge Size option
347 max_size = htobe16(size);
348 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
349 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
355 *_optoffset = optoffset;
362 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
364 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
365 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
367 return dhcp_network_send_raw_socket(client->fd, &client->link,
371 static int client_send_discover(sd_dhcp_client *client) {
372 _cleanup_free_ DHCPPacket *discover = NULL;
373 size_t optoffset, optlen;
378 assert(client->state == DHCP_STATE_INIT ||
379 client->state == DHCP_STATE_SELECTING);
381 /* See RFC2131 section 4.4.1 */
383 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
386 assert(time_now >= client->start_time);
388 /* seconds between sending first and last DISCOVER
389 * must always be strictly positive to deal with broken servers */
390 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
392 r = client_message_init(client, &discover, DHCP_DISCOVER,
393 &optlen, &optoffset);
397 /* the client may suggest values for the network address
398 and lease time in the DHCPDISCOVER message. The client may include
399 the ’requested IP address’ option to suggest that a particular IP
400 address be assigned, and may include the ’IP address lease time’
401 option to suggest the lease time it would like.
403 if (client->last_addr != INADDR_ANY) {
404 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
405 DHCP_OPTION_REQUESTED_IP_ADDRESS,
406 4, &client->last_addr);
411 /* it is unclear from RFC 2131 if client should send hostname in
412 DHCPDISCOVER but dhclient does and so we do as well
414 if (client->hostname) {
415 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
416 DHCP_OPTION_HOST_NAME,
417 strlen(client->hostname), client->hostname);
422 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
423 DHCP_OPTION_END, 0, NULL);
427 /* We currently ignore:
428 The client SHOULD wait a random time between one and ten seconds to
429 desynchronize the use of DHCP at startup.
431 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
435 log_dhcp_client(client, "DISCOVER");
440 static int client_send_request(sd_dhcp_client *client) {
441 _cleanup_free_ DHCPPacket *request = NULL;
442 size_t optoffset, optlen;
445 r = client_message_init(client, &request, DHCP_REQUEST,
446 &optlen, &optoffset);
450 switch (client->state) {
451 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
452 SELECTING should be REQUESTING)
455 case DHCP_STATE_REQUESTING:
456 /* Client inserts the address of the selected server in ’server
457 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
458 filled in with the yiaddr value from the chosen DHCPOFFER.
461 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
462 DHCP_OPTION_SERVER_IDENTIFIER,
463 4, &client->lease->server_address);
467 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
468 DHCP_OPTION_REQUESTED_IP_ADDRESS,
469 4, &client->lease->address);
475 case DHCP_STATE_INIT_REBOOT:
476 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
477 option MUST be filled in with client’s notion of its previously
478 assigned address. ’ciaddr’ MUST be zero.
480 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
481 DHCP_OPTION_REQUESTED_IP_ADDRESS,
482 4, &client->last_addr);
487 case DHCP_STATE_RENEWING:
488 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
489 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
490 client’s IP address.
494 case DHCP_STATE_REBINDING:
495 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
496 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
497 client’s IP address.
499 This message MUST be broadcast to the 0xffffffff IP broadcast address.
501 request->dhcp.ciaddr = client->lease->address;
505 case DHCP_STATE_INIT:
506 case DHCP_STATE_SELECTING:
507 case DHCP_STATE_REBOOTING:
508 case DHCP_STATE_BOUND:
509 case DHCP_STATE_STOPPED:
513 if (client->hostname) {
514 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
515 DHCP_OPTION_HOST_NAME,
516 strlen(client->hostname), client->hostname);
521 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
522 DHCP_OPTION_END, 0, NULL);
526 if (client->state == DHCP_STATE_RENEWING) {
527 r = dhcp_network_send_udp_socket(client->fd,
528 client->lease->server_address,
531 sizeof(DHCPMessage) + optoffset);
533 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
538 switch (client->state) {
539 case DHCP_STATE_REQUESTING:
540 log_dhcp_client(client, "REQUEST (requesting)");
542 case DHCP_STATE_INIT_REBOOT:
543 log_dhcp_client(client, "REQUEST (init-reboot)");
545 case DHCP_STATE_RENEWING:
546 log_dhcp_client(client, "REQUEST (renewing)");
548 case DHCP_STATE_REBINDING:
549 log_dhcp_client(client, "REQUEST (rebinding)");
552 log_dhcp_client(client, "REQUEST (invalid)");
559 static int client_start(sd_dhcp_client *client);
561 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
563 sd_dhcp_client *client = userdata;
564 DHCP_CLIENT_DONT_DESTROY(client);
565 usec_t next_timeout = 0;
572 assert(client->event);
574 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
578 switch (client->state) {
579 case DHCP_STATE_RENEWING:
581 time_left = (client->lease->t2 - client->lease->t1) / 2;
585 next_timeout = time_now + time_left * USEC_PER_SEC;
589 case DHCP_STATE_REBINDING:
591 time_left = (client->lease->lifetime - client->lease->t2) / 2;
595 next_timeout = time_now + time_left * USEC_PER_SEC;
598 case DHCP_STATE_REBOOTING:
599 /* start over as we did not receive a timely ack or nak */
600 r = client_initialize(client);
604 r = client_start(client);
608 log_dhcp_client(client, "REBOOTED");
612 case DHCP_STATE_INIT:
613 case DHCP_STATE_INIT_REBOOT:
614 case DHCP_STATE_SELECTING:
615 case DHCP_STATE_REQUESTING:
616 case DHCP_STATE_BOUND:
618 if (client->attempt < 64)
619 client->attempt *= 2;
621 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
625 case DHCP_STATE_STOPPED:
630 next_timeout += (random_u32() & 0x1fffff);
632 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
634 r = sd_event_add_time(client->event,
635 &client->timeout_resend,
637 next_timeout, 10 * USEC_PER_MSEC,
638 client_timeout_resend, client);
642 r = sd_event_source_set_priority(client->timeout_resend,
643 client->event_priority);
647 switch (client->state) {
648 case DHCP_STATE_INIT:
649 r = client_send_discover(client);
651 client->state = DHCP_STATE_SELECTING;
654 if (client->attempt >= 64)
660 case DHCP_STATE_SELECTING:
661 r = client_send_discover(client);
662 if (r < 0 && client->attempt >= 64)
667 case DHCP_STATE_INIT_REBOOT:
668 case DHCP_STATE_REQUESTING:
669 case DHCP_STATE_RENEWING:
670 case DHCP_STATE_REBINDING:
671 r = client_send_request(client);
672 if (r < 0 && client->attempt >= 64)
675 if (client->state == DHCP_STATE_INIT_REBOOT)
676 client->state = DHCP_STATE_REBOOTING;
678 client->request_sent = time_now;
682 case DHCP_STATE_REBOOTING:
683 case DHCP_STATE_BOUND:
687 case DHCP_STATE_STOPPED:
695 client_stop(client, r);
697 /* Errors were dealt with when stopping the client, don't spill
698 errors into the event loop handler */
702 static int client_initialize_events(sd_dhcp_client *client,
703 sd_event_io_handler_t io_callback) {
707 assert(client->event);
709 r = sd_event_add_io(client->event, &client->receive_message,
710 client->fd, EPOLLIN, io_callback,
715 r = sd_event_source_set_priority(client->receive_message,
716 client->event_priority);
720 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
722 r = sd_event_add_time(client->event,
723 &client->timeout_resend,
726 client_timeout_resend, client);
730 r = sd_event_source_set_priority(client->timeout_resend,
731 client->event_priority);
735 client_stop(client, r);
741 static int client_start(sd_dhcp_client *client) {
744 assert_return(client, -EINVAL);
745 assert_return(client->event, -EINVAL);
746 assert_return(client->index > 0, -EINVAL);
747 assert_return(client->fd < 0, -EBUSY);
748 assert_return(client->xid == 0, -EINVAL);
749 assert_return(client->state == DHCP_STATE_INIT ||
750 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
752 client->xid = random_u32();
754 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
756 client_stop(client, r);
761 if (client->state == DHCP_STATE_INIT) {
762 client->start_time = now(CLOCK_MONOTONIC);
766 return client_initialize_events(client, client_receive_message_raw);
769 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
771 sd_dhcp_client *client = userdata;
772 DHCP_CLIENT_DONT_DESTROY(client);
774 log_dhcp_client(client, "EXPIRED");
776 client_notify(client, DHCP_EVENT_EXPIRED);
778 /* lease was lost, start over if not freed or stopped in callback */
779 if (client->state != DHCP_STATE_STOPPED) {
780 client_initialize(client);
781 client_start(client);
787 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
788 sd_dhcp_client *client = userdata;
789 DHCP_CLIENT_DONT_DESTROY(client);
792 client->receive_message = sd_event_source_unref(client->receive_message);
793 client->fd = asynchronous_close(client->fd);
795 client->state = DHCP_STATE_REBINDING;
798 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
800 client_stop(client, r);
805 return client_initialize_events(client, client_receive_message_raw);
808 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
810 sd_dhcp_client *client = userdata;
811 DHCP_CLIENT_DONT_DESTROY(client);
814 client->state = DHCP_STATE_RENEWING;
817 r = dhcp_network_bind_udp_socket(client->lease->address,
820 log_dhcp_client(client, "could not bind UDP socket");
826 return client_initialize_events(client, client_receive_message_udp);
829 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
831 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
834 r = dhcp_lease_new(&lease);
838 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
839 if (r != DHCP_OFFER) {
840 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
844 lease->next_server = offer->siaddr;
846 lease->address = offer->yiaddr;
848 if (lease->address == INADDR_ANY ||
849 lease->server_address == INADDR_ANY ||
850 lease->lifetime == 0) {
851 log_dhcp_client(client, "receieved lease lacks address, server "
852 "address or lease lifetime, ignoring");
856 if (lease->subnet_mask == INADDR_ANY) {
857 r = dhcp_lease_set_default_subnet_mask(lease);
859 log_dhcp_client(client, "receieved lease lacks subnet "
860 "mask, and a fallback one can not be "
861 "generated, ignoring");
866 sd_dhcp_lease_unref(client->lease);
867 client->lease = lease;
870 log_dhcp_client(client, "OFFER");
875 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
877 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
880 r = dhcp_lease_new(&lease);
884 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
886 log_dhcp_client(client, "NAK");
887 return DHCP_EVENT_NO_LEASE;
891 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
895 lease->next_server = ack->siaddr;
897 lease->address = ack->yiaddr;
899 if (lease->address == INADDR_ANY ||
900 lease->server_address == INADDR_ANY ||
901 lease->lifetime == 0) {
902 log_dhcp_client(client, "receieved lease lacks address, server "
903 "address or lease lifetime, ignoring");
907 if (lease->subnet_mask == INADDR_ANY) {
908 r = dhcp_lease_set_default_subnet_mask(lease);
910 log_dhcp_client(client, "receieved lease lacks subnet "
911 "mask, and a fallback one can not be "
912 "generated, ignoring");
917 r = DHCP_EVENT_IP_ACQUIRE;
919 if (client->lease->address != lease->address ||
920 client->lease->subnet_mask != lease->subnet_mask ||
921 client->lease->router != lease->router) {
922 r = DHCP_EVENT_IP_CHANGE;
924 r = DHCP_EVENT_RENEW;
926 client->lease = sd_dhcp_lease_unref(client->lease);
929 client->lease = lease;
932 log_dhcp_client(client, "ACK");
937 static uint64_t client_compute_timeout(sd_dhcp_client *client,
938 uint32_t lifetime, double factor) {
940 assert(client->request_sent);
943 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
944 + (random_u32() & 0x1fffff);
947 static int client_set_lease_timeouts(sd_dhcp_client *client) {
949 uint64_t lifetime_timeout;
952 char time_string[FORMAT_TIMESPAN_MAX];
956 assert(client->event);
957 assert(client->lease);
958 assert(client->lease->lifetime);
960 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
961 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
962 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
964 /* don't set timers for infinite leases */
965 if (client->lease->lifetime == 0xffffffff)
968 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
971 assert(client->request_sent <= time_now);
973 /* convert the various timeouts from relative (secs) to absolute (usecs) */
974 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
975 if (client->lease->t1 && client->lease->t2) {
976 /* both T1 and T2 are given */
977 if (client->lease->t1 < client->lease->t2 &&
978 client->lease->t2 < client->lease->lifetime) {
979 /* they are both valid */
980 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
981 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
984 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
985 client->lease->t2 = (client->lease->lifetime * 7) / 8;
986 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
987 client->lease->t1 = client->lease->lifetime / 2;
989 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
990 /* only T2 is given, and it is valid */
991 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
992 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
993 client->lease->t1 = client->lease->lifetime / 2;
994 if (t2_timeout <= t1_timeout) {
995 /* the computed T1 would be invalid, so discard T2 */
996 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
997 client->lease->t2 = (client->lease->lifetime * 7) / 8;
999 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
1000 /* only T1 is given, and it is valid */
1001 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1002 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1003 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1004 if (t2_timeout <= t1_timeout) {
1005 /* the computed T2 would be invalid, so discard T1 */
1006 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1007 client->lease->t2 = client->lease->lifetime / 2;
1010 /* fall back to the default timeouts */
1011 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1012 client->lease->t1 = client->lease->lifetime / 2;
1013 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1014 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1017 /* arm lifetime timeout */
1018 r = sd_event_add_time(client->event, &client->timeout_expire,
1020 lifetime_timeout, 10 * USEC_PER_MSEC,
1021 client_timeout_expire, client);
1025 r = sd_event_source_set_priority(client->timeout_expire,
1026 client->event_priority);
1030 log_dhcp_client(client, "lease expires in %s",
1031 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1032 lifetime_timeout - time_now, 0));
1034 /* don't arm earlier timeouts if this has already expired */
1035 if (lifetime_timeout <= time_now)
1038 /* arm T2 timeout */
1039 r = sd_event_add_time(client->event,
1040 &client->timeout_t2,
1044 client_timeout_t2, client);
1048 r = sd_event_source_set_priority(client->timeout_t2,
1049 client->event_priority);
1053 log_dhcp_client(client, "T2 expires in %s",
1054 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1055 t2_timeout - time_now, 0));
1057 /* don't arm earlier timeout if this has already expired */
1058 if (t2_timeout <= time_now)
1061 /* arm T1 timeout */
1062 r = sd_event_add_time(client->event,
1063 &client->timeout_t1,
1065 t1_timeout, 10 * USEC_PER_MSEC,
1066 client_timeout_t1, client);
1070 r = sd_event_source_set_priority(client->timeout_t1,
1071 client->event_priority);
1075 log_dhcp_client(client, "T1 expires in %s",
1076 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1077 t1_timeout - time_now, 0));
1082 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1084 DHCP_CLIENT_DONT_DESTROY(client);
1085 int r = 0, notify_event = 0;
1088 assert(client->event);
1091 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1092 log_dhcp_client(client, "not a DHCP message: ignoring");
1096 if (message->op != BOOTREPLY) {
1097 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1101 if (be32toh(message->xid) != client->xid) {
1102 log_dhcp_client(client, "received xid (%u) does not match "
1103 "expected (%u): ignoring",
1104 be32toh(message->xid), client->xid);
1108 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1109 log_dhcp_client(client, "not an ethernet packet");
1113 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1115 log_dhcp_client(client, "received chaddr does not match "
1116 "expected: ignoring");
1120 switch (client->state) {
1121 case DHCP_STATE_SELECTING:
1123 r = client_handle_offer(client, message, len);
1126 client->timeout_resend =
1127 sd_event_source_unref(client->timeout_resend);
1129 client->state = DHCP_STATE_REQUESTING;
1130 client->attempt = 1;
1132 r = sd_event_add_time(client->event,
1133 &client->timeout_resend,
1136 client_timeout_resend, client);
1140 r = sd_event_source_set_priority(client->timeout_resend,
1141 client->event_priority);
1144 } else if (r == -ENOMSG)
1145 /* invalid message, let's ignore it */
1150 case DHCP_STATE_REBOOTING:
1151 case DHCP_STATE_REQUESTING:
1152 case DHCP_STATE_RENEWING:
1153 case DHCP_STATE_REBINDING:
1155 r = client_handle_ack(client, message, len);
1156 if (r == DHCP_EVENT_NO_LEASE) {
1158 client->timeout_resend =
1159 sd_event_source_unref(client->timeout_resend);
1161 if (client->state == DHCP_STATE_REBOOTING) {
1162 r = client_initialize(client);
1166 r = client_start(client);
1170 log_dhcp_client(client, "REBOOTED");
1174 } else if (r >= 0) {
1175 client->timeout_resend =
1176 sd_event_source_unref(client->timeout_resend);
1178 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1179 DHCP_STATE_REBOOTING))
1180 notify_event = DHCP_EVENT_IP_ACQUIRE;
1181 else if (r != DHCP_EVENT_IP_ACQUIRE)
1184 client->state = DHCP_STATE_BOUND;
1185 client->attempt = 1;
1187 client->last_addr = client->lease->address;
1189 r = client_set_lease_timeouts(client);
1194 client_notify(client, notify_event);
1195 if (client->state == DHCP_STATE_STOPPED)
1199 client->receive_message =
1200 sd_event_source_unref(client->receive_message);
1201 client->fd = asynchronous_close(client->fd);
1202 } else if (r == -ENOMSG)
1203 /* invalid message, let's ignore it */
1208 case DHCP_STATE_INIT:
1209 case DHCP_STATE_INIT_REBOOT:
1210 case DHCP_STATE_BOUND:
1214 case DHCP_STATE_STOPPED:
1220 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1221 client_stop(client, r);
1226 static int client_receive_message_udp(sd_event_source *s, int fd,
1227 uint32_t revents, void *userdata) {
1228 sd_dhcp_client *client = userdata;
1229 _cleanup_free_ DHCPMessage *message = NULL;
1230 int buflen = 0, len, r;
1235 r = ioctl(fd, FIONREAD, &buflen);
1240 /* this can't be right */
1243 message = malloc0(buflen);
1247 len = read(fd, message, buflen);
1249 log_dhcp_client(client, "could not receive message from UDP "
1252 } else if ((size_t)len < sizeof(DHCPMessage))
1255 return client_handle_message(client, message, len);
1258 static int client_receive_message_raw(sd_event_source *s, int fd,
1259 uint32_t revents, void *userdata) {
1260 sd_dhcp_client *client = userdata;
1261 _cleanup_free_ DHCPPacket *packet = NULL;
1262 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1263 struct iovec iov = {};
1264 struct msghdr msg = {
1267 .msg_control = cmsgbuf,
1268 .msg_controllen = sizeof(cmsgbuf),
1270 struct cmsghdr *cmsg;
1271 bool checksum = true;
1272 int buflen = 0, len, r;
1277 r = ioctl(fd, FIONREAD, &buflen);
1282 /* this can't be right */
1285 packet = malloc0(buflen);
1289 iov.iov_base = packet;
1290 iov.iov_len = buflen;
1292 len = recvmsg(fd, &msg, 0);
1294 log_dhcp_client(client, "could not receive message from raw "
1297 } else if ((size_t)len < sizeof(DHCPPacket))
1300 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1301 if (cmsg->cmsg_level == SOL_PACKET &&
1302 cmsg->cmsg_type == PACKET_AUXDATA &&
1303 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1304 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1306 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1311 r = dhcp_packet_verify_headers(packet, len, checksum);
1315 len -= DHCP_IP_UDP_SIZE;
1317 return client_handle_message(client, &packet->dhcp, len);
1320 int sd_dhcp_client_start(sd_dhcp_client *client) {
1323 assert_return(client, -EINVAL);
1325 r = client_initialize(client);
1329 if (client->last_addr)
1330 client->state = DHCP_STATE_INIT_REBOOT;
1332 r = client_start(client);
1334 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1336 ether_ntoa(&client->client_id.mac_addr));
1341 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1342 DHCP_CLIENT_DONT_DESTROY(client);
1344 assert_return(client, -EINVAL);
1346 client_stop(client, DHCP_EVENT_STOP);
1347 client->state = DHCP_STATE_STOPPED;
1352 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1356 assert_return(client, -EINVAL);
1357 assert_return(!client->event, -EBUSY);
1360 client->event = sd_event_ref(event);
1362 r = sd_event_default(&client->event);
1367 client->event_priority = priority;
1372 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1373 assert_return(client, -EINVAL);
1375 client->event = sd_event_unref(client->event);
1380 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1384 return client->event;
1387 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1389 assert_se(REFCNT_INC(client->n_ref) >= 2);
1394 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1395 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1396 log_dhcp_client(client, "FREE");
1398 client_initialize(client);
1400 client->receive_message =
1401 sd_event_source_unref(client->receive_message);
1403 sd_dhcp_client_detach_event(client);
1405 sd_dhcp_lease_unref(client->lease);
1407 free(client->req_opts);
1408 free(client->hostname);
1415 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1416 _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1418 assert_return(ret, -EINVAL);
1420 client = new0(sd_dhcp_client, 1);
1424 client->n_ref = REFCNT_INIT;
1425 client->state = DHCP_STATE_INIT;
1428 client->attempt = 1;
1430 client->req_opts_size = ELEMENTSOF(default_req_opts);
1432 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1433 if (!client->req_opts)