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, DHCPPacket **ret,
260 uint8_t type, size_t *_optlen, size_t *_optoffset) {
261 _cleanup_free_ DHCPPacket *packet;
262 size_t optlen, optoffset, size;
267 assert(client->secs);
271 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
273 optlen = DHCP_MIN_OPTIONS_SIZE;
274 size = sizeof(DHCPPacket) + optlen;
276 packet = malloc0(size);
280 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
285 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
286 refuse to issue an DHCP lease if 'secs' is set to zero */
287 packet->dhcp.secs = htobe16(client->secs);
289 /* RFC2132 section 4.1.1:
290 The client MUST include its hardware address in the ’chaddr’ field, if
291 necessary for delivery of DHCP reply messages.
293 memcpy(&packet->dhcp.chaddr, &client->client_id.mac_addr, ETH_ALEN);
295 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
296 Identifier option is not set */
297 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
298 DHCP_OPTION_CLIENT_IDENTIFIER,
299 sizeof(client->client_id), &client->client_id);
304 /* RFC2131 section 3.5:
305 in its initial DHCPDISCOVER or DHCPREQUEST message, a
306 client may provide the server with a list of specific
307 parameters the client is interested in. If the client
308 includes a list of parameters in a DHCPDISCOVER message,
309 it MUST include that list in any subsequent DHCPREQUEST
312 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
313 DHCP_OPTION_PARAMETER_REQUEST_LIST,
314 client->req_opts_size, client->req_opts);
318 /* RFC2131 section 3.5:
319 The client SHOULD include the ’maximum DHCP message size’ option to
320 let the server know how large the server may make its DHCP messages.
322 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
323 than the defined default size unless the Maximum Messge Size option
326 max_size = htobe16(size);
327 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
328 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
334 *_optoffset = optoffset;
341 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
343 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
344 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
346 return dhcp_network_send_raw_socket(client->fd, &client->link,
350 static int client_send_discover(sd_dhcp_client *client) {
351 _cleanup_free_ DHCPPacket *discover = NULL;
352 size_t optoffset, optlen;
357 assert(client->state == DHCP_STATE_INIT ||
358 client->state == DHCP_STATE_SELECTING);
360 /* See RFC2131 section 4.4.1 */
362 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
365 assert(time_now >= client->start_time);
367 /* seconds between sending first and last DISCOVER
368 * must always be strictly positive to deal with broken servers */
369 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
371 r = client_message_init(client, &discover, DHCP_DISCOVER,
372 &optlen, &optoffset);
376 /* the client may suggest values for the network address
377 and lease time in the DHCPDISCOVER message. The client may include
378 the ’requested IP address’ option to suggest that a particular IP
379 address be assigned, and may include the ’IP address lease time’
380 option to suggest the lease time it would like.
382 if (client->last_addr != INADDR_ANY) {
383 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
384 DHCP_OPTION_REQUESTED_IP_ADDRESS,
385 4, &client->last_addr);
390 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
391 DHCP_OPTION_END, 0, NULL);
393 /* We currently ignore:
394 The client SHOULD wait a random time between one and ten seconds to
395 desynchronize the use of DHCP at startup.
397 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
401 log_dhcp_client(client, "DISCOVER");
406 static int client_send_request(sd_dhcp_client *client) {
407 _cleanup_free_ DHCPPacket *request;
408 size_t optoffset, optlen;
411 r = client_message_init(client, &request, DHCP_REQUEST,
412 &optlen, &optoffset);
416 switch (client->state) {
417 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
418 SELECTING should be REQUESTING)
421 case DHCP_STATE_REQUESTING:
422 /* Client inserts the address of the selected server in ’server
423 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
424 filled in with the yiaddr value from the chosen DHCPOFFER.
427 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
428 DHCP_OPTION_SERVER_IDENTIFIER,
429 4, &client->lease->server_address);
433 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
434 DHCP_OPTION_REQUESTED_IP_ADDRESS,
435 4, &client->lease->address);
441 case DHCP_STATE_INIT_REBOOT:
442 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
443 option MUST be filled in with client’s notion of its previously
444 assigned address. ’ciaddr’ MUST be zero.
446 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
447 DHCP_OPTION_REQUESTED_IP_ADDRESS,
448 4, &client->last_addr);
453 case DHCP_STATE_RENEWING:
454 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
455 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
456 client’s IP address.
460 case DHCP_STATE_REBINDING:
461 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
462 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
463 client’s IP address.
465 This message MUST be broadcast to the 0xffffffff IP broadcast address.
467 request->dhcp.ciaddr = client->lease->address;
471 case DHCP_STATE_INIT:
472 case DHCP_STATE_SELECTING:
473 case DHCP_STATE_REBOOTING:
474 case DHCP_STATE_BOUND:
475 case DHCP_STATE_STOPPED:
479 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
480 DHCP_OPTION_END, 0, NULL);
484 if (client->state == DHCP_STATE_RENEWING) {
485 r = dhcp_network_send_udp_socket(client->fd,
486 client->lease->server_address,
489 sizeof(DHCPMessage) + optoffset);
491 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
496 switch (client->state) {
497 case DHCP_STATE_REQUESTING:
498 log_dhcp_client(client, "REQUEST (requesting)");
500 case DHCP_STATE_INIT_REBOOT:
501 log_dhcp_client(client, "REQUEST (init-reboot)");
503 case DHCP_STATE_RENEWING:
504 log_dhcp_client(client, "REQUEST (renewing)");
506 case DHCP_STATE_REBINDING:
507 log_dhcp_client(client, "REQUEST (rebinding)");
510 log_dhcp_client(client, "REQUEST (invalid)");
517 static int client_start(sd_dhcp_client *client);
519 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
521 sd_dhcp_client *client = userdata;
522 usec_t next_timeout = 0;
529 assert(client->event);
531 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
535 switch (client->state) {
536 case DHCP_STATE_RENEWING:
538 time_left = (client->lease->t2 - client->lease->t1) / 2;
542 next_timeout = time_now + time_left * USEC_PER_SEC;
546 case DHCP_STATE_REBINDING:
548 time_left = (client->lease->lifetime - client->lease->t2) / 2;
552 next_timeout = time_now + time_left * USEC_PER_SEC;
555 case DHCP_STATE_REBOOTING:
556 /* start over as we did not receive a timely ack or nak */
557 r = client_initialize(client);
561 r = client_start(client);
565 log_dhcp_client(client, "REBOOTED");
569 case DHCP_STATE_INIT:
570 case DHCP_STATE_INIT_REBOOT:
571 case DHCP_STATE_SELECTING:
572 case DHCP_STATE_REQUESTING:
573 case DHCP_STATE_BOUND:
575 if (client->attempt < 64)
576 client->attempt *= 2;
578 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
582 case DHCP_STATE_STOPPED:
587 next_timeout += (random_u32() & 0x1fffff);
589 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
591 r = sd_event_add_time(client->event,
592 &client->timeout_resend,
594 next_timeout, 10 * USEC_PER_MSEC,
595 client_timeout_resend, client);
599 r = sd_event_source_set_priority(client->timeout_resend,
600 client->event_priority);
604 switch (client->state) {
605 case DHCP_STATE_INIT:
606 r = client_send_discover(client);
608 client->state = DHCP_STATE_SELECTING;
611 if (client->attempt >= 64)
617 case DHCP_STATE_SELECTING:
618 r = client_send_discover(client);
619 if (r < 0 && client->attempt >= 64)
624 case DHCP_STATE_INIT_REBOOT:
625 case DHCP_STATE_REQUESTING:
626 case DHCP_STATE_RENEWING:
627 case DHCP_STATE_REBINDING:
628 r = client_send_request(client);
629 if (r < 0 && client->attempt >= 64)
632 if (client->state == DHCP_STATE_INIT_REBOOT)
633 client->state = DHCP_STATE_REBOOTING;
635 client->request_sent = time_now;
639 case DHCP_STATE_REBOOTING:
640 case DHCP_STATE_BOUND:
644 case DHCP_STATE_STOPPED:
652 client_stop(client, r);
654 /* Errors were dealt with when stopping the client, don't spill
655 errors into the event loop handler */
659 static int client_initialize_events(sd_dhcp_client *client,
660 sd_event_io_handler_t io_callback) {
664 assert(client->event);
666 r = sd_event_add_io(client->event, &client->receive_message,
667 client->fd, EPOLLIN, io_callback,
672 r = sd_event_source_set_priority(client->receive_message,
673 client->event_priority);
677 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
679 r = sd_event_add_time(client->event,
680 &client->timeout_resend,
683 client_timeout_resend, client);
687 r = sd_event_source_set_priority(client->timeout_resend,
688 client->event_priority);
692 client_stop(client, r);
698 static int client_start(sd_dhcp_client *client) {
701 assert_return(client, -EINVAL);
702 assert_return(client->event, -EINVAL);
703 assert_return(client->index > 0, -EINVAL);
704 assert_return(client->fd < 0, -EBUSY);
705 assert_return(client->xid == 0, -EINVAL);
706 assert_return(client->state == DHCP_STATE_INIT ||
707 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
709 client->xid = random_u32();
711 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
713 client_stop(client, r);
718 if (client->state == DHCP_STATE_INIT) {
719 client->start_time = now(CLOCK_MONOTONIC);
723 return client_initialize_events(client, client_receive_message_raw);
726 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
728 sd_dhcp_client *client = userdata;
730 log_dhcp_client(client, "EXPIRED");
732 client = client_notify(client, DHCP_EVENT_EXPIRED);
734 /* lease was lost, start over if not freed or stopped in callback */
735 if (client && client->state != DHCP_STATE_STOPPED) {
736 client_initialize(client);
737 client_start(client);
743 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
744 sd_dhcp_client *client = userdata;
747 client->receive_message = sd_event_source_unref(client->receive_message);
748 client->fd = asynchronous_close(client->fd);
750 client->state = DHCP_STATE_REBINDING;
753 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
755 client_stop(client, r);
760 return client_initialize_events(client, client_receive_message_raw);
763 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
765 sd_dhcp_client *client = userdata;
768 client->state = DHCP_STATE_RENEWING;
771 r = dhcp_network_bind_udp_socket(client->lease->address,
774 client_stop(client, r);
780 return client_initialize_events(client, client_receive_message_udp);
783 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
785 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
788 r = dhcp_lease_new(&lease);
792 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
793 if (r != DHCP_OFFER) {
794 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
798 lease->next_server = offer->siaddr;
800 lease->address = offer->yiaddr;
802 if (lease->address == INADDR_ANY ||
803 lease->server_address == INADDR_ANY ||
804 lease->lifetime == 0) {
805 log_dhcp_client(client, "receieved lease lacks address, server "
806 "address or lease lifetime, ignoring");
810 if (lease->subnet_mask == INADDR_ANY) {
811 r = dhcp_lease_set_default_subnet_mask(lease);
813 log_dhcp_client(client, "receieved lease lacks subnet "
814 "mask, and a fallback one can not be "
815 "generated, ignoring");
820 sd_dhcp_lease_unref(client->lease);
821 client->lease = lease;
824 log_dhcp_client(client, "OFFER");
829 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
831 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
834 r = dhcp_lease_new(&lease);
838 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
840 log_dhcp_client(client, "NAK");
841 return DHCP_EVENT_NO_LEASE;
845 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
849 lease->next_server = ack->siaddr;
851 lease->address = ack->yiaddr;
853 if (lease->address == INADDR_ANY ||
854 lease->server_address == INADDR_ANY ||
855 lease->lifetime == 0) {
856 log_dhcp_client(client, "receieved lease lacks address, server "
857 "address or lease lifetime, ignoring");
861 if (lease->subnet_mask == INADDR_ANY) {
862 r = dhcp_lease_set_default_subnet_mask(lease);
864 log_dhcp_client(client, "receieved lease lacks subnet "
865 "mask, and a fallback one can not be "
866 "generated, ignoring");
871 r = DHCP_EVENT_IP_ACQUIRE;
873 if (client->lease->address != lease->address ||
874 client->lease->subnet_mask != lease->subnet_mask ||
875 client->lease->router != lease->router) {
876 r = DHCP_EVENT_IP_CHANGE;
879 client->lease = sd_dhcp_lease_unref(client->lease);
882 client->lease = lease;
885 log_dhcp_client(client, "ACK");
890 static uint64_t client_compute_timeout(sd_dhcp_client *client,
891 uint32_t lifetime, double factor) {
893 assert(client->request_sent);
896 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
897 + (random_u32() & 0x1fffff);
900 static int client_set_lease_timeouts(sd_dhcp_client *client) {
902 uint64_t lifetime_timeout;
905 char time_string[FORMAT_TIMESPAN_MAX];
909 assert(client->event);
910 assert(client->lease);
911 assert(client->lease->lifetime);
913 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
914 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
915 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
917 /* don't set timers for infinite leases */
918 if (client->lease->lifetime == 0xffffffff)
921 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
924 assert(client->request_sent <= time_now);
926 /* convert the various timeouts from relative (secs) to absolute (usecs) */
927 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
928 if (client->lease->t1 && client->lease->t2) {
929 /* both T1 and T2 are given */
930 if (client->lease->t1 < client->lease->t2 &&
931 client->lease->t2 < client->lease->lifetime) {
932 /* they are both valid */
933 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
934 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
937 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
938 client->lease->t2 = (client->lease->lifetime * 7) / 8;
939 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
940 client->lease->t1 = client->lease->lifetime / 2;
942 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
943 /* only T2 is given, and it is valid */
944 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
945 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
946 client->lease->t1 = client->lease->lifetime / 2;
947 if (t2_timeout <= t1_timeout) {
948 /* the computed T1 would be invalid, so discard T2 */
949 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
950 client->lease->t2 = (client->lease->lifetime * 7) / 8;
952 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
953 /* only T1 is given, and it is valid */
954 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
955 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
956 client->lease->t2 = (client->lease->lifetime * 7) / 8;
957 if (t2_timeout <= t1_timeout) {
958 /* the computed T2 would be invalid, so discard T1 */
959 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
960 client->lease->t2 = client->lease->lifetime / 2;
963 /* fall back to the default timeouts */
964 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
965 client->lease->t1 = client->lease->lifetime / 2;
966 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
967 client->lease->t2 = (client->lease->lifetime * 7) / 8;
970 /* arm lifetime timeout */
971 r = sd_event_add_time(client->event, &client->timeout_expire,
973 lifetime_timeout, 10 * USEC_PER_MSEC,
974 client_timeout_expire, client);
978 r = sd_event_source_set_priority(client->timeout_expire,
979 client->event_priority);
983 log_dhcp_client(client, "lease expires in %s",
984 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
985 lifetime_timeout - time_now, 0));
987 /* don't arm earlier timeouts if this has already expired */
988 if (lifetime_timeout <= time_now)
992 r = sd_event_add_time(client->event,
997 client_timeout_t2, client);
1001 r = sd_event_source_set_priority(client->timeout_t2,
1002 client->event_priority);
1006 log_dhcp_client(client, "T2 expires in %s",
1007 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1008 t2_timeout - time_now, 0));
1010 /* don't arm earlier timeout if this has already expired */
1011 if (t2_timeout <= time_now)
1014 /* arm T1 timeout */
1015 r = sd_event_add_time(client->event,
1016 &client->timeout_t1,
1018 t1_timeout, 10 * USEC_PER_MSEC,
1019 client_timeout_t1, client);
1023 r = sd_event_source_set_priority(client->timeout_t1,
1024 client->event_priority);
1028 log_dhcp_client(client, "T1 expires in %s",
1029 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1030 t1_timeout - time_now, 0));
1035 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1037 int r = 0, notify_event = 0;
1040 assert(client->event);
1043 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1044 log_dhcp_client(client, "not a DHCP message: ignoring");
1048 if (message->op != BOOTREPLY) {
1049 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1053 if (be32toh(message->xid) != client->xid) {
1054 log_dhcp_client(client, "received xid (%u) does not match "
1055 "expected (%u): ignoring",
1056 be32toh(message->xid), client->xid);
1060 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1061 log_dhcp_client(client, "not an ethernet packet");
1065 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1067 log_dhcp_client(client, "received chaddr does not match "
1068 "expected: ignoring");
1072 switch (client->state) {
1073 case DHCP_STATE_SELECTING:
1075 r = client_handle_offer(client, message, len);
1078 client->timeout_resend =
1079 sd_event_source_unref(client->timeout_resend);
1081 client->state = DHCP_STATE_REQUESTING;
1082 client->attempt = 1;
1084 r = sd_event_add_time(client->event,
1085 &client->timeout_resend,
1088 client_timeout_resend, client);
1092 r = sd_event_source_set_priority(client->timeout_resend,
1093 client->event_priority);
1096 } else if (r == -ENOMSG)
1097 /* invalid message, let's ignore it */
1102 case DHCP_STATE_REBOOTING:
1103 case DHCP_STATE_REQUESTING:
1104 case DHCP_STATE_RENEWING:
1105 case DHCP_STATE_REBINDING:
1107 r = client_handle_ack(client, message, len);
1108 if (r == DHCP_EVENT_NO_LEASE) {
1110 client->timeout_resend =
1111 sd_event_source_unref(client->timeout_resend);
1113 if (client->state == DHCP_STATE_REBOOTING) {
1114 r = client_initialize(client);
1118 r = client_start(client);
1122 log_dhcp_client(client, "REBOOTED");
1126 } else if (r >= 0) {
1127 client->timeout_resend =
1128 sd_event_source_unref(client->timeout_resend);
1130 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1131 DHCP_STATE_REBOOTING))
1132 notify_event = DHCP_EVENT_IP_ACQUIRE;
1133 else if (r != DHCP_EVENT_IP_ACQUIRE)
1136 client->state = DHCP_STATE_BOUND;
1137 client->attempt = 1;
1139 client->last_addr = client->lease->address;
1141 r = client_set_lease_timeouts(client);
1146 client = client_notify(client, notify_event);
1148 client->state == DHCP_STATE_STOPPED)
1152 client->receive_message =
1153 sd_event_source_unref(client->receive_message);
1154 client->fd = asynchronous_close(client->fd);
1155 } else if (r == -ENOMSG)
1156 /* invalid message, let's ignore it */
1161 case DHCP_STATE_INIT:
1162 case DHCP_STATE_INIT_REBOOT:
1163 case DHCP_STATE_BOUND:
1167 case DHCP_STATE_STOPPED:
1173 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1174 client_stop(client, r);
1179 static int client_receive_message_udp(sd_event_source *s, int fd,
1180 uint32_t revents, void *userdata) {
1181 sd_dhcp_client *client = userdata;
1182 _cleanup_free_ DHCPMessage *message = NULL;
1183 int buflen = 0, len, r;
1188 r = ioctl(fd, FIONREAD, &buflen);
1193 /* this can't be right */
1196 message = malloc0(buflen);
1200 len = read(fd, message, buflen);
1202 log_dhcp_client(client, "could not receive message from UDP "
1203 "socket: %s", strerror(errno));
1205 } else if ((size_t)len < sizeof(DHCPMessage))
1208 return client_handle_message(client, message, len);
1211 static int client_receive_message_raw(sd_event_source *s, int fd,
1212 uint32_t revents, void *userdata) {
1213 sd_dhcp_client *client = userdata;
1214 _cleanup_free_ DHCPPacket *packet = NULL;
1215 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1216 struct iovec iov = {};
1217 struct msghdr msg = {
1220 .msg_control = cmsgbuf,
1221 .msg_controllen = sizeof(cmsgbuf),
1223 struct cmsghdr *cmsg;
1224 bool checksum = true;
1225 int buflen = 0, len, r;
1230 r = ioctl(fd, FIONREAD, &buflen);
1235 /* this can't be right */
1238 packet = malloc0(buflen);
1242 iov.iov_base = packet;
1243 iov.iov_len = buflen;
1245 len = recvmsg(fd, &msg, 0);
1247 log_dhcp_client(client, "could not receive message from raw "
1248 "socket: %s", strerror(errno));
1250 } else if ((size_t)len < sizeof(DHCPPacket))
1253 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1254 if (cmsg->cmsg_level == SOL_PACKET &&
1255 cmsg->cmsg_type == PACKET_AUXDATA &&
1256 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1257 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1259 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1264 r = dhcp_packet_verify_headers(packet, len, checksum);
1268 len -= DHCP_IP_UDP_SIZE;
1270 return client_handle_message(client, &packet->dhcp, len);
1273 int sd_dhcp_client_start(sd_dhcp_client *client) {
1276 assert_return(client, -EINVAL);
1278 r = client_initialize(client);
1282 if (client->last_addr)
1283 client->state = DHCP_STATE_INIT_REBOOT;
1285 r = client_start(client);
1287 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1289 ether_ntoa(&client->client_id.mac_addr));
1294 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1295 assert_return(client, -EINVAL);
1297 if (client_stop(client, DHCP_EVENT_STOP))
1298 client->state = DHCP_STATE_STOPPED;
1303 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1307 assert_return(client, -EINVAL);
1308 assert_return(!client->event, -EBUSY);
1311 client->event = sd_event_ref(event);
1313 r = sd_event_default(&client->event);
1318 client->event_priority = priority;
1323 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1324 assert_return(client, -EINVAL);
1326 client->event = sd_event_unref(client->event);
1331 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1335 return client->event;
1338 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1340 assert_se(REFCNT_INC(client->n_ref) >= 2);
1345 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1346 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1347 log_dhcp_client(client, "UNREF");
1349 client_initialize(client);
1351 client->receive_message =
1352 sd_event_source_unref(client->receive_message);
1354 sd_dhcp_client_detach_event(client);
1356 sd_dhcp_lease_unref(client->lease);
1358 free(client->req_opts);
1367 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
1368 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1370 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1371 _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1373 assert_return(ret, -EINVAL);
1375 client = new0(sd_dhcp_client, 1);
1379 client->n_ref = REFCNT_INIT;
1380 client->state = DHCP_STATE_INIT;
1383 client->attempt = 1;
1385 client->req_opts_size = ELEMENTSOF(default_req_opts);
1387 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1388 if (!client->req_opts)