2 This file is part of systemd.
4 Copyright (C) 2013 Intel Corporation. All rights reserved.
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <net/ethernet.h>
25 #include <net/if_arp.h>
26 #include <netinet/ether.h>
27 #include <sys/param.h>
28 #include <sys/ioctl.h>
34 #include "dhcp-protocol.h"
35 #include "dhcp-internal.h"
36 #include "dhcp-lease-internal.h"
37 #include "sd-dhcp-client.h"
39 struct sd_dhcp_client {
45 sd_event_source *timeout_resend;
48 union sockaddr_union link;
49 sd_event_source *receive_message;
51 size_t req_opts_allocated;
56 struct ether_addr mac_addr;
63 sd_event_source *timeout_t1;
64 sd_event_source *timeout_t2;
65 sd_event_source *timeout_expire;
66 sd_dhcp_client_cb_t cb;
71 static const uint8_t default_req_opts[] = {
72 DHCP_OPTION_SUBNET_MASK,
74 DHCP_OPTION_HOST_NAME,
75 DHCP_OPTION_DOMAIN_NAME,
76 DHCP_OPTION_DOMAIN_NAME_SERVER,
77 DHCP_OPTION_NTP_SERVER,
80 static int client_receive_message_raw(sd_event_source *s, int fd,
81 uint32_t revents, void *userdata);
82 static int client_receive_message_udp(sd_event_source *s, int fd,
83 uint32_t revents, void *userdata);
84 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error);
86 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
88 assert_return(client, -EINVAL);
91 client->userdata = userdata;
96 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
99 assert_return(client, -EINVAL);
100 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
101 DHCP_STATE_STOPPED), -EBUSY);
104 case DHCP_OPTION_PAD:
105 case DHCP_OPTION_OVERLOAD:
106 case DHCP_OPTION_MESSAGE_TYPE:
107 case DHCP_OPTION_PARAMETER_REQUEST_LIST:
108 case DHCP_OPTION_END:
115 for (i = 0; i < client->req_opts_size; i++)
116 if (client->req_opts[i] == option)
119 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
120 client->req_opts_size + 1))
123 client->req_opts[client->req_opts_size++] = option;
128 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
129 const struct in_addr *last_addr) {
130 assert_return(client, -EINVAL);
131 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
132 DHCP_STATE_STOPPED), -EBUSY);
135 client->last_addr = last_addr->s_addr;
137 client->last_addr = INADDR_ANY;
142 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
143 assert_return(client, -EINVAL);
144 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
145 DHCP_STATE_STOPPED), -EBUSY);
146 assert_return(interface_index > 0, -EINVAL);
148 client->index = interface_index;
153 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
154 const struct ether_addr *addr) {
155 bool need_restart = false;
157 assert_return(client, -EINVAL);
158 assert_return(addr, -EINVAL);
160 if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
163 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
164 log_dhcp_client(client, "Changing MAC address on running DHCP "
165 "client, restarting");
167 client = client_stop(client, DHCP_EVENT_STOP);
173 memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
174 client->client_id.type = 0x01;
176 if (need_restart && client->state != DHCP_STATE_STOPPED)
177 sd_dhcp_client_start(client);
182 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
183 assert_return(client, -EINVAL);
184 assert_return(ret, -EINVAL);
186 if (client->state != DHCP_STATE_BOUND &&
187 client->state != DHCP_STATE_RENEWING &&
188 client->state != DHCP_STATE_REBINDING)
189 return -EADDRNOTAVAIL;
191 *ret = sd_dhcp_lease_ref(client->lease);
196 static sd_dhcp_client *client_notify(sd_dhcp_client *client, int event) {
198 client = sd_dhcp_client_ref(client);
199 client->cb(client, event, client->userdata);
200 client = sd_dhcp_client_unref(client);
206 static int client_initialize(sd_dhcp_client *client) {
207 assert_return(client, -EINVAL);
209 client->receive_message =
210 sd_event_source_unref(client->receive_message);
212 client->fd = safe_close(client->fd);
214 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
216 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
217 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
218 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
222 client->state = DHCP_STATE_INIT;
226 client->lease = sd_dhcp_lease_unref(client->lease);
231 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error) {
232 assert_return(client, NULL);
235 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
238 case DHCP_EVENT_STOP:
239 log_dhcp_client(client, "STOPPED: Requested by user");
241 case DHCP_EVENT_NO_LEASE:
242 log_dhcp_client(client, "STOPPED: No lease");
245 log_dhcp_client(client, "STOPPED: Unknown reason");
250 client = client_notify(client, error);
253 client_initialize(client);
258 static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
259 uint8_t type, uint8_t **opt, size_t *optlen) {
264 assert(client->secs);
268 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
270 r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt,
275 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
276 refuse to issue an DHCP lease if 'secs' is set to zero */
277 message->secs = htobe16(client->secs);
279 /* RFC2132 section 4.1.1:
280 The client MUST include its hardware address in the ’chaddr’ field, if
281 necessary for delivery of DHCP reply messages.
283 memcpy(&message->chaddr, &client->client_id.mac_addr, ETH_ALEN);
285 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
286 Identifier option is not set */
287 r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
288 sizeof(client->client_id), &client->client_id);
293 /* RFC2131 section 3.5:
294 in its initial DHCPDISCOVER or DHCPREQUEST message, a
295 client may provide the server with a list of specific
296 parameters the client is interested in. If the client
297 includes a list of parameters in a DHCPDISCOVER message,
298 it MUST include that list in any subsequent DHCPREQUEST
301 r = dhcp_option_append(opt, optlen,
302 DHCP_OPTION_PARAMETER_REQUEST_LIST,
303 client->req_opts_size,
308 /* RFC2131 section 3.5:
309 The client SHOULD include the ’maximum DHCP message size’ option to
310 let the server know how large the server may make its DHCP messages.
312 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
313 than the defined default size unless the Maximum Messge Size option
316 max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
317 DHCP_MIN_OPTIONS_SIZE);
318 r = dhcp_option_append(opt, optlen,
319 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
327 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
329 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
330 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
332 return dhcp_network_send_raw_socket(client->fd, &client->link,
336 static int client_send_discover(sd_dhcp_client *client) {
337 _cleanup_free_ DHCPPacket *discover = NULL;
344 assert(client->state == DHCP_STATE_INIT ||
345 client->state == DHCP_STATE_SELECTING);
347 /* See RFC2131 section 4.4.1 */
349 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
352 assert(time_now >= client->start_time);
354 /* seconds between sending first and last DISCOVER
355 * must always be strictly positive to deal with broken servers */
356 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
358 optlen = DHCP_MIN_OPTIONS_SIZE;
359 len = sizeof(DHCPPacket) + optlen;
361 discover = malloc0(len);
365 r = client_message_init(client, &discover->dhcp, DHCP_DISCOVER,
370 /* the client may suggest values for the network address
371 and lease time in the DHCPDISCOVER message. The client may include
372 the ’requested IP address’ option to suggest that a particular IP
373 address be assigned, and may include the ’IP address lease time’
374 option to suggest the lease time it would like.
376 if (client->last_addr != INADDR_ANY) {
377 r = dhcp_option_append(&opt, &optlen,
378 DHCP_OPTION_REQUESTED_IP_ADDRESS,
379 4, &client->last_addr);
384 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
388 /* We currently ignore:
389 The client SHOULD wait a random time between one and ten seconds to
390 desynchronize the use of DHCP at startup.
392 r = dhcp_client_send_raw(client, discover, len - optlen);
396 log_dhcp_client(client, "DISCOVER");
401 static int client_send_request(sd_dhcp_client *client) {
402 _cleanup_free_ DHCPPacket *request;
407 optlen = DHCP_MIN_OPTIONS_SIZE;
408 len = sizeof(DHCPPacket) + optlen;
410 request = malloc0(len);
414 r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt,
419 switch (client->state) {
420 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
421 SELECTING should be REQUESTING)
424 case DHCP_STATE_REQUESTING:
425 /* Client inserts the address of the selected server in ’server
426 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
427 filled in with the yiaddr value from the chosen DHCPOFFER.
430 r = dhcp_option_append(&opt, &optlen,
431 DHCP_OPTION_SERVER_IDENTIFIER,
432 4, &client->lease->server_address);
436 r = dhcp_option_append(&opt, &optlen,
437 DHCP_OPTION_REQUESTED_IP_ADDRESS,
438 4, &client->lease->address);
444 case DHCP_STATE_INIT_REBOOT:
445 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
446 option MUST be filled in with client’s notion of its previously
447 assigned address. ’ciaddr’ MUST be zero.
449 r = dhcp_option_append(&opt, &optlen,
450 DHCP_OPTION_REQUESTED_IP_ADDRESS,
451 4, &client->last_addr);
456 case DHCP_STATE_RENEWING:
457 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
458 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
459 client’s IP address.
463 case DHCP_STATE_REBINDING:
464 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
465 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
466 client’s IP address.
468 This message MUST be broadcast to the 0xffffffff IP broadcast address.
470 request->dhcp.ciaddr = client->lease->address;
474 case DHCP_STATE_INIT:
475 case DHCP_STATE_SELECTING:
476 case DHCP_STATE_REBOOTING:
477 case DHCP_STATE_BOUND:
478 case DHCP_STATE_STOPPED:
482 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
486 if (client->state == DHCP_STATE_RENEWING) {
487 r = dhcp_network_send_udp_socket(client->fd,
488 client->lease->server_address,
491 len - optlen - DHCP_IP_UDP_SIZE);
493 r = dhcp_client_send_raw(client, request, len - optlen);
498 switch (client->state) {
499 case DHCP_STATE_REQUESTING:
500 log_dhcp_client(client, "REQUEST (requesting)");
502 case DHCP_STATE_INIT_REBOOT:
503 log_dhcp_client(client, "REQUEST (init-reboot)");
505 case DHCP_STATE_RENEWING:
506 log_dhcp_client(client, "REQUEST (renewing)");
508 case DHCP_STATE_REBINDING:
509 log_dhcp_client(client, "REQUEST (rebinding)");
512 log_dhcp_client(client, "REQUEST (invalid)");
519 static int client_start(sd_dhcp_client *client);
521 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
523 sd_dhcp_client *client = userdata;
524 usec_t next_timeout = 0;
531 assert(client->event);
533 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
537 switch (client->state) {
538 case DHCP_STATE_RENEWING:
540 time_left = (client->lease->t2 - client->lease->t1) / 2;
544 next_timeout = time_now + time_left * USEC_PER_SEC;
548 case DHCP_STATE_REBINDING:
550 time_left = (client->lease->lifetime - client->lease->t2) / 2;
554 next_timeout = time_now + time_left * USEC_PER_SEC;
557 case DHCP_STATE_REBOOTING:
558 /* start over as we did not receive a timely ack or nak */
559 r = client_initialize(client);
563 r = client_start(client);
567 log_dhcp_client(client, "REBOOTED");
571 case DHCP_STATE_INIT:
572 case DHCP_STATE_INIT_REBOOT:
573 case DHCP_STATE_SELECTING:
574 case DHCP_STATE_REQUESTING:
575 case DHCP_STATE_BOUND:
577 if (client->attempt < 64)
578 client->attempt *= 2;
580 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
584 case DHCP_STATE_STOPPED:
589 next_timeout += (random_u32() & 0x1fffff);
591 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
593 r = sd_event_add_time(client->event,
594 &client->timeout_resend,
596 next_timeout, 10 * USEC_PER_MSEC,
597 client_timeout_resend, client);
601 r = sd_event_source_set_priority(client->timeout_resend,
602 client->event_priority);
606 switch (client->state) {
607 case DHCP_STATE_INIT:
608 r = client_send_discover(client);
610 client->state = DHCP_STATE_SELECTING;
613 if (client->attempt >= 64)
619 case DHCP_STATE_SELECTING:
620 r = client_send_discover(client);
621 if (r < 0 && client->attempt >= 64)
626 case DHCP_STATE_INIT_REBOOT:
627 case DHCP_STATE_REQUESTING:
628 case DHCP_STATE_RENEWING:
629 case DHCP_STATE_REBINDING:
630 r = client_send_request(client);
631 if (r < 0 && client->attempt >= 64)
634 if (client->state == DHCP_STATE_INIT_REBOOT)
635 client->state = DHCP_STATE_REBOOTING;
637 client->request_sent = time_now;
641 case DHCP_STATE_REBOOTING:
642 case DHCP_STATE_BOUND:
646 case DHCP_STATE_STOPPED:
654 client_stop(client, r);
656 /* Errors were dealt with when stopping the client, don't spill
657 errors into the event loop handler */
661 static int client_initialize_events(sd_dhcp_client *client,
662 sd_event_io_handler_t io_callback) {
666 assert(client->event);
668 r = sd_event_add_io(client->event, &client->receive_message,
669 client->fd, EPOLLIN, io_callback,
674 r = sd_event_source_set_priority(client->receive_message,
675 client->event_priority);
679 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
681 r = sd_event_add_time(client->event,
682 &client->timeout_resend,
685 client_timeout_resend, client);
689 r = sd_event_source_set_priority(client->timeout_resend,
690 client->event_priority);
694 client_stop(client, r);
700 static int client_start(sd_dhcp_client *client) {
703 assert_return(client, -EINVAL);
704 assert_return(client->event, -EINVAL);
705 assert_return(client->index > 0, -EINVAL);
706 assert_return(client->fd < 0, -EBUSY);
707 assert_return(client->xid == 0, -EINVAL);
708 assert_return(client->state == DHCP_STATE_INIT ||
709 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
711 client->xid = random_u32();
713 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
715 client_stop(client, r);
720 if (client->state == DHCP_STATE_INIT) {
721 client->start_time = now(CLOCK_MONOTONIC);
725 return client_initialize_events(client, client_receive_message_raw);
728 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
730 sd_dhcp_client *client = userdata;
732 log_dhcp_client(client, "EXPIRED");
734 client = client_notify(client, DHCP_EVENT_EXPIRED);
736 /* lease was lost, start over if not freed or stopped in callback */
737 if (client && client->state != DHCP_STATE_STOPPED) {
738 client_initialize(client);
739 client_start(client);
745 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
746 sd_dhcp_client *client = userdata;
749 client->receive_message = sd_event_source_unref(client->receive_message);
750 client->fd = safe_close(client->fd);
752 client->state = DHCP_STATE_REBINDING;
755 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
757 client_stop(client, r);
762 return client_initialize_events(client, client_receive_message_raw);
765 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
767 sd_dhcp_client *client = userdata;
770 client->state = DHCP_STATE_RENEWING;
773 r = dhcp_network_bind_udp_socket(client->index,
774 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 = safe_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)