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 <sys/param.h>
27 #include <sys/ioctl.h>
33 #include "dhcp-protocol.h"
34 #include "dhcp-internal.h"
35 #include "dhcp-lease-internal.h"
36 #include "sd-dhcp-client.h"
38 struct sd_dhcp_client {
44 sd_event_source *timeout_resend;
47 union sockaddr_union link;
48 sd_event_source *receive_message;
50 size_t req_opts_allocated;
55 struct ether_addr mac_addr;
62 sd_event_source *timeout_t1;
63 sd_event_source *timeout_t2;
64 sd_event_source *timeout_expire;
65 sd_dhcp_client_cb_t cb;
70 static const uint8_t default_req_opts[] = {
71 DHCP_OPTION_SUBNET_MASK,
73 DHCP_OPTION_HOST_NAME,
74 DHCP_OPTION_DOMAIN_NAME,
75 DHCP_OPTION_DOMAIN_NAME_SERVER,
76 DHCP_OPTION_NTP_SERVER,
79 static int client_receive_message_raw(sd_event_source *s, int fd,
80 uint32_t revents, void *userdata);
81 static int client_receive_message_udp(sd_event_source *s, int fd,
82 uint32_t revents, void *userdata);
83 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error);
85 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
87 assert_return(client, -EINVAL);
90 client->userdata = userdata;
95 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
98 assert_return(client, -EINVAL);
99 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
100 DHCP_STATE_STOPPED), -EBUSY);
103 case DHCP_OPTION_PAD:
104 case DHCP_OPTION_OVERLOAD:
105 case DHCP_OPTION_MESSAGE_TYPE:
106 case DHCP_OPTION_PARAMETER_REQUEST_LIST:
107 case DHCP_OPTION_END:
114 for (i = 0; i < client->req_opts_size; i++)
115 if (client->req_opts[i] == option)
118 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
119 client->req_opts_size + 1))
122 client->req_opts[client->req_opts_size++] = option;
127 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
128 const struct in_addr *last_addr) {
129 assert_return(client, -EINVAL);
130 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
131 DHCP_STATE_STOPPED), -EBUSY);
134 client->last_addr = last_addr->s_addr;
136 client->last_addr = INADDR_ANY;
141 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
142 assert_return(client, -EINVAL);
143 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
144 DHCP_STATE_STOPPED), -EBUSY);
145 assert_return(interface_index >= -1, -EINVAL);
147 client->index = interface_index;
152 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
153 const struct ether_addr *addr) {
154 bool need_restart = false;
156 assert_return(client, -EINVAL);
157 assert_return(addr, -EINVAL);
159 if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
162 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
163 log_dhcp_client(client, "Changing MAC address on running DHCP "
164 "client, restarting");
166 client = client_stop(client, DHCP_EVENT_STOP);
172 memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
173 client->client_id.type = 0x01;
175 if (need_restart && client->state != DHCP_STATE_STOPPED)
176 sd_dhcp_client_start(client);
181 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
182 assert_return(client, -EINVAL);
183 assert_return(ret, -EINVAL);
185 if (client->state != DHCP_STATE_BOUND &&
186 client->state != DHCP_STATE_RENEWING &&
187 client->state != DHCP_STATE_REBINDING)
188 return -EADDRNOTAVAIL;
190 *ret = sd_dhcp_lease_ref(client->lease);
195 static sd_dhcp_client *client_notify(sd_dhcp_client *client, int event) {
197 client = sd_dhcp_client_ref(client);
198 client->cb(client, event, client->userdata);
199 client = sd_dhcp_client_unref(client);
205 static int client_initialize(sd_dhcp_client *client) {
206 assert_return(client, -EINVAL);
208 client->receive_message =
209 sd_event_source_unref(client->receive_message);
211 client->fd = safe_close(client->fd);
213 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
215 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
216 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
217 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
221 client->state = DHCP_STATE_INIT;
225 client->lease = sd_dhcp_lease_unref(client->lease);
230 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error) {
231 assert_return(client, NULL);
233 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
235 client = client_notify(client, error);
238 client_initialize(client);
243 static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
244 uint8_t type, uint8_t **opt, size_t *optlen) {
249 assert(client->secs);
253 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
255 r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt,
260 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
261 refuse to issue an DHCP lease if 'secs' is set to zero */
262 message->secs = htobe16(client->secs);
264 /* RFC2132 section 4.1.1:
265 The client MUST include its hardware address in the ’chaddr’ field, if
266 necessary for delivery of DHCP reply messages.
268 memcpy(&message->chaddr, &client->client_id.mac_addr, ETH_ALEN);
270 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
271 Identifier option is not set */
272 r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
273 sizeof(client->client_id), &client->client_id);
278 /* RFC2131 section 3.5:
279 in its initial DHCPDISCOVER or DHCPREQUEST message, a
280 client may provide the server with a list of specific
281 parameters the client is interested in. If the client
282 includes a list of parameters in a DHCPDISCOVER message,
283 it MUST include that list in any subsequent DHCPREQUEST
286 r = dhcp_option_append(opt, optlen,
287 DHCP_OPTION_PARAMETER_REQUEST_LIST,
288 client->req_opts_size,
293 /* RFC2131 section 3.5:
294 The client SHOULD include the ’maximum DHCP message size’ option to
295 let the server know how large the server may make its DHCP messages.
297 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
298 than the defined default size unless the Maximum Messge Size option
301 max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
302 DHCP_MIN_OPTIONS_SIZE);
303 r = dhcp_option_append(opt, optlen,
304 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
312 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
314 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
315 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
317 return dhcp_network_send_raw_socket(client->fd, &client->link,
321 static int client_send_discover(sd_dhcp_client *client) {
322 _cleanup_free_ DHCPPacket *discover = NULL;
329 assert(client->state == DHCP_STATE_INIT ||
330 client->state == DHCP_STATE_SELECTING);
332 /* See RFC2131 section 4.4.1 */
334 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
337 assert(time_now >= client->start_time);
339 /* seconds between sending first and last DISCOVER
340 * must always be strictly positive to deal with broken servers */
341 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
343 optlen = DHCP_MIN_OPTIONS_SIZE;
344 len = sizeof(DHCPPacket) + optlen;
346 discover = malloc0(len);
350 r = client_message_init(client, &discover->dhcp, DHCP_DISCOVER,
355 /* the client may suggest values for the network address
356 and lease time in the DHCPDISCOVER message. The client may include
357 the ’requested IP address’ option to suggest that a particular IP
358 address be assigned, and may include the ’IP address lease time’
359 option to suggest the lease time it would like.
361 if (client->last_addr != INADDR_ANY) {
362 r = dhcp_option_append(&opt, &optlen,
363 DHCP_OPTION_REQUESTED_IP_ADDRESS,
364 4, &client->last_addr);
369 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
373 /* We currently ignore:
374 The client SHOULD wait a random time between one and ten seconds to
375 desynchronize the use of DHCP at startup.
377 r = dhcp_client_send_raw(client, discover, len - optlen);
381 log_dhcp_client(client, "DISCOVER");
386 static int client_send_request(sd_dhcp_client *client) {
387 _cleanup_free_ DHCPPacket *request;
392 optlen = DHCP_MIN_OPTIONS_SIZE;
393 len = sizeof(DHCPPacket) + optlen;
395 request = malloc0(len);
399 r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt,
404 switch (client->state) {
405 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
406 SELECTING should be REQUESTING)
409 case DHCP_STATE_REQUESTING:
410 /* Client inserts the address of the selected server in ’server
411 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
412 filled in with the yiaddr value from the chosen DHCPOFFER.
415 r = dhcp_option_append(&opt, &optlen,
416 DHCP_OPTION_SERVER_IDENTIFIER,
417 4, &client->lease->server_address);
421 r = dhcp_option_append(&opt, &optlen,
422 DHCP_OPTION_REQUESTED_IP_ADDRESS,
423 4, &client->lease->address);
429 case DHCP_STATE_INIT_REBOOT:
430 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
431 option MUST be filled in with client’s notion of its previously
432 assigned address. ’ciaddr’ MUST be zero.
434 r = dhcp_option_append(&opt, &optlen,
435 DHCP_OPTION_REQUESTED_IP_ADDRESS,
436 4, &client->last_addr);
441 case DHCP_STATE_RENEWING:
442 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
443 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
444 client’s IP address.
448 case DHCP_STATE_REBINDING:
449 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
450 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
451 client’s IP address.
453 This message MUST be broadcast to the 0xffffffff IP broadcast address.
455 request->dhcp.ciaddr = client->lease->address;
459 case DHCP_STATE_INIT:
460 case DHCP_STATE_SELECTING:
461 case DHCP_STATE_REBOOTING:
462 case DHCP_STATE_BOUND:
463 case DHCP_STATE_STOPPED:
467 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
471 if (client->state == DHCP_STATE_RENEWING) {
472 r = dhcp_network_send_udp_socket(client->fd,
473 client->lease->server_address,
476 len - optlen - DHCP_IP_UDP_SIZE);
478 r = dhcp_client_send_raw(client, request, len - optlen);
483 switch (client->state) {
484 case DHCP_STATE_REQUESTING:
485 log_dhcp_client(client, "REQUEST (requesting)");
487 case DHCP_STATE_INIT_REBOOT:
488 log_dhcp_client(client, "REQUEST (init-reboot)");
490 case DHCP_STATE_RENEWING:
491 log_dhcp_client(client, "REQUEST (renewing)");
493 case DHCP_STATE_REBINDING:
494 log_dhcp_client(client, "REQUEST (rebinding)");
497 log_dhcp_client(client, "REQUEST (invalid)");
504 static int client_start(sd_dhcp_client *client);
506 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
508 sd_dhcp_client *client = userdata;
509 usec_t next_timeout = 0;
516 assert(client->event);
518 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
522 switch (client->state) {
523 case DHCP_STATE_RENEWING:
525 time_left = (client->lease->t2 - client->lease->t1) / 2;
529 next_timeout = time_now + time_left * USEC_PER_SEC;
533 case DHCP_STATE_REBINDING:
535 time_left = (client->lease->lifetime - client->lease->t2) / 2;
539 next_timeout = time_now + time_left * USEC_PER_SEC;
542 case DHCP_STATE_REBOOTING:
543 /* start over as we did not receive a timely ack or nak */
544 r = client_initialize(client);
548 r = client_start(client);
552 log_dhcp_client(client, "REBOOTED");
556 case DHCP_STATE_INIT:
557 case DHCP_STATE_INIT_REBOOT:
558 case DHCP_STATE_SELECTING:
559 case DHCP_STATE_REQUESTING:
560 case DHCP_STATE_BOUND:
562 if (client->attempt < 64)
563 client->attempt *= 2;
565 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
569 case DHCP_STATE_STOPPED:
574 next_timeout += (random_u32() & 0x1fffff);
576 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
578 r = sd_event_add_time(client->event,
579 &client->timeout_resend,
581 next_timeout, 10 * USEC_PER_MSEC,
582 client_timeout_resend, client);
586 r = sd_event_source_set_priority(client->timeout_resend,
587 client->event_priority);
591 switch (client->state) {
592 case DHCP_STATE_INIT:
593 r = client_send_discover(client);
595 client->state = DHCP_STATE_SELECTING;
598 if (client->attempt >= 64)
604 case DHCP_STATE_SELECTING:
605 r = client_send_discover(client);
606 if (r < 0 && client->attempt >= 64)
611 case DHCP_STATE_INIT_REBOOT:
612 case DHCP_STATE_REQUESTING:
613 case DHCP_STATE_RENEWING:
614 case DHCP_STATE_REBINDING:
615 r = client_send_request(client);
616 if (r < 0 && client->attempt >= 64)
619 if (client->state == DHCP_STATE_INIT_REBOOT)
620 client->state = DHCP_STATE_REBOOTING;
622 client->request_sent = time_now;
626 case DHCP_STATE_REBOOTING:
627 case DHCP_STATE_BOUND:
631 case DHCP_STATE_STOPPED:
639 client_stop(client, r);
641 /* Errors were dealt with when stopping the client, don't spill
642 errors into the event loop handler */
646 static int client_initialize_events(sd_dhcp_client *client,
647 sd_event_io_handler_t io_callback) {
651 assert(client->event);
653 r = sd_event_add_io(client->event, &client->receive_message,
654 client->fd, EPOLLIN, io_callback,
659 r = sd_event_source_set_priority(client->receive_message,
660 client->event_priority);
664 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
666 r = sd_event_add_time(client->event,
667 &client->timeout_resend,
670 client_timeout_resend, client);
674 r = sd_event_source_set_priority(client->timeout_resend,
675 client->event_priority);
679 client_stop(client, r);
685 static int client_start(sd_dhcp_client *client) {
688 assert_return(client, -EINVAL);
689 assert_return(client->event, -EINVAL);
690 assert_return(client->index > 0, -EINVAL);
691 assert_return(client->fd < 0, -EBUSY);
692 assert_return(client->xid == 0, -EINVAL);
693 assert_return(client->state == DHCP_STATE_INIT ||
694 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
696 client->xid = random_u32();
698 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
700 client_stop(client, r);
705 if (client->state == DHCP_STATE_INIT) {
706 client->start_time = now(CLOCK_MONOTONIC);
710 return client_initialize_events(client, client_receive_message_raw);
713 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
715 sd_dhcp_client *client = userdata;
717 log_dhcp_client(client, "EXPIRED");
719 client = client_notify(client, DHCP_EVENT_EXPIRED);
721 /* lease was lost, start over if not freed or stopped in callback */
722 if (client && client->state != DHCP_STATE_STOPPED) {
723 client_initialize(client);
724 client_start(client);
730 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
731 sd_dhcp_client *client = userdata;
734 client->receive_message = sd_event_source_unref(client->receive_message);
735 client->fd = safe_close(client->fd);
737 client->state = DHCP_STATE_REBINDING;
740 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
742 client_stop(client, r);
747 return client_initialize_events(client, client_receive_message_raw);
750 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
752 sd_dhcp_client *client = userdata;
755 client->state = DHCP_STATE_RENEWING;
758 r = dhcp_network_bind_udp_socket(client->index,
759 client->lease->address,
762 client_stop(client, r);
768 return client_initialize_events(client, client_receive_message_udp);
771 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
773 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
776 r = dhcp_lease_new(&lease);
780 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
781 if (r != DHCP_OFFER) {
782 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
786 lease->next_server = offer->siaddr;
788 lease->address = offer->yiaddr;
790 if (lease->address == INADDR_ANY ||
791 lease->server_address == INADDR_ANY ||
792 lease->lifetime == 0) {
793 log_dhcp_client(client, "receieved lease lacks address, server "
794 "address or lease lifetime, ignoring");
798 if (lease->subnet_mask == INADDR_ANY) {
799 r = dhcp_lease_set_default_subnet_mask(lease);
801 log_dhcp_client(client, "receieved lease lacks subnet "
802 "mask, and a fallback one can not be "
803 "generated, ignoring");
808 client->lease = lease;
811 log_dhcp_client(client, "OFFER");
816 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
818 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
821 r = dhcp_lease_new(&lease);
825 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
827 log_dhcp_client(client, "NAK");
828 return DHCP_EVENT_NO_LEASE;
832 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
836 lease->next_server = ack->siaddr;
838 lease->address = ack->yiaddr;
840 if (lease->address == INADDR_ANY ||
841 lease->server_address == INADDR_ANY ||
842 lease->lifetime == 0) {
843 log_dhcp_client(client, "receieved lease lacks address, server "
844 "address or lease lifetime, ignoring");
848 if (lease->subnet_mask == INADDR_ANY) {
849 r = dhcp_lease_set_default_subnet_mask(lease);
851 log_dhcp_client(client, "receieved lease lacks subnet "
852 "mask, and a fallback one can not be "
853 "generated, ignoring");
858 r = DHCP_EVENT_IP_ACQUIRE;
860 if (client->lease->address != lease->address ||
861 client->lease->subnet_mask != lease->subnet_mask ||
862 client->lease->router != lease->router) {
863 r = DHCP_EVENT_IP_CHANGE;
866 client->lease = sd_dhcp_lease_unref(client->lease);
869 client->lease = lease;
872 log_dhcp_client(client, "ACK");
877 static uint64_t client_compute_timeout(sd_dhcp_client *client,
878 uint32_t lifetime, double factor) {
880 assert(client->request_sent);
883 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
884 + (random_u32() & 0x1fffff);
887 static int client_set_lease_timeouts(sd_dhcp_client *client) {
889 uint64_t lifetime_timeout;
892 char time_string[FORMAT_TIMESPAN_MAX];
896 assert(client->event);
897 assert(client->lease);
898 assert(client->lease->lifetime);
900 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
901 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
902 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
904 /* don't set timers for infinite leases */
905 if (client->lease->lifetime == 0xffffffff)
908 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
911 assert(client->request_sent <= time_now);
913 /* convert the various timeouts from relative (secs) to absolute (usecs) */
914 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
915 if (client->lease->t1 && client->lease->t2) {
916 /* both T1 and T2 are given */
917 if (client->lease->t1 < client->lease->t2 &&
918 client->lease->t2 < client->lease->lifetime) {
919 /* they are both valid */
920 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
921 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
924 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
925 client->lease->t2 = (client->lease->lifetime * 7) / 8;
926 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
927 client->lease->t1 = client->lease->lifetime / 2;
929 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
930 /* only T2 is given, and it is valid */
931 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
932 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
933 client->lease->t1 = client->lease->lifetime / 2;
934 if (t2_timeout <= t1_timeout) {
935 /* the computed T1 would be invalid, so discard T2 */
936 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
937 client->lease->t2 = (client->lease->lifetime * 7) / 8;
939 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
940 /* only T1 is given, and it is valid */
941 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
942 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
943 client->lease->t2 = (client->lease->lifetime * 7) / 8;
944 if (t2_timeout <= t1_timeout) {
945 /* the computed T2 would be invalid, so discard T1 */
946 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
947 client->lease->t2 = client->lease->lifetime / 2;
950 /* fall back to the default timeouts */
951 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
952 client->lease->t1 = client->lease->lifetime / 2;
953 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
954 client->lease->t2 = (client->lease->lifetime * 7) / 8;
957 /* arm lifetime timeout */
958 r = sd_event_add_time(client->event, &client->timeout_expire,
960 lifetime_timeout, 10 * USEC_PER_MSEC,
961 client_timeout_expire, client);
965 r = sd_event_source_set_priority(client->timeout_expire,
966 client->event_priority);
970 log_dhcp_client(client, "lease expires in %s",
971 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
972 lifetime_timeout - time_now, 0));
974 /* don't arm earlier timeouts if this has already expired */
975 if (lifetime_timeout <= time_now)
979 r = sd_event_add_time(client->event,
984 client_timeout_t2, client);
988 r = sd_event_source_set_priority(client->timeout_t2,
989 client->event_priority);
993 log_dhcp_client(client, "T2 expires in %s",
994 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
995 t2_timeout - time_now, 0));
997 /* don't arm earlier timeout if this has already expired */
998 if (t2_timeout <= time_now)
1001 /* arm T1 timeout */
1002 r = sd_event_add_time(client->event,
1003 &client->timeout_t1,
1005 t1_timeout, 10 * USEC_PER_MSEC,
1006 client_timeout_t1, client);
1010 r = sd_event_source_set_priority(client->timeout_t1,
1011 client->event_priority);
1015 log_dhcp_client(client, "T1 expires in %s",
1016 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1017 t1_timeout - time_now, 0));
1022 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1024 int r = 0, notify_event = 0;
1027 assert(client->event);
1030 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1031 log_dhcp_client(client, "not a DHCP message: ignoring");
1035 if (message->op != BOOTREPLY) {
1036 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1040 if (be32toh(message->xid) != client->xid) {
1041 log_dhcp_client(client, "received xid (%u) does not match "
1042 "expected (%u): ignoring",
1043 be32toh(message->xid), client->xid);
1047 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1048 log_dhcp_client(client, "not an ethernet packet");
1052 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1054 log_dhcp_client(client, "received chaddr does not match "
1055 "expected: ignoring");
1059 switch (client->state) {
1060 case DHCP_STATE_SELECTING:
1062 r = client_handle_offer(client, message, len);
1065 client->timeout_resend =
1066 sd_event_source_unref(client->timeout_resend);
1068 client->state = DHCP_STATE_REQUESTING;
1069 client->attempt = 1;
1071 r = sd_event_add_time(client->event,
1072 &client->timeout_resend,
1075 client_timeout_resend, client);
1079 r = sd_event_source_set_priority(client->timeout_resend,
1080 client->event_priority);
1083 } else if (r == -ENOMSG)
1084 /* invalid message, let's ignore it */
1089 case DHCP_STATE_REBOOTING:
1090 case DHCP_STATE_REQUESTING:
1091 case DHCP_STATE_RENEWING:
1092 case DHCP_STATE_REBINDING:
1094 r = client_handle_ack(client, message, len);
1095 if (r == DHCP_EVENT_NO_LEASE) {
1097 client->timeout_resend =
1098 sd_event_source_unref(client->timeout_resend);
1100 if (client->state == DHCP_STATE_REBOOTING) {
1101 r = client_initialize(client);
1105 r = client_start(client);
1109 log_dhcp_client(client, "REBOOTED");
1113 } else if (r >= 0) {
1114 client->timeout_resend =
1115 sd_event_source_unref(client->timeout_resend);
1117 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1118 DHCP_STATE_REBOOTING))
1119 notify_event = DHCP_EVENT_IP_ACQUIRE;
1120 else if (r != DHCP_EVENT_IP_ACQUIRE)
1123 client->state = DHCP_STATE_BOUND;
1124 client->attempt = 1;
1126 client->last_addr = client->lease->address;
1128 r = client_set_lease_timeouts(client);
1133 client = client_notify(client, notify_event);
1135 client->state == DHCP_STATE_STOPPED)
1139 client->receive_message =
1140 sd_event_source_unref(client->receive_message);
1141 client->fd = safe_close(client->fd);
1142 } else if (r == -ENOMSG)
1143 /* invalid message, let's ignore it */
1148 case DHCP_STATE_INIT:
1149 case DHCP_STATE_INIT_REBOOT:
1150 case DHCP_STATE_BOUND:
1154 case DHCP_STATE_STOPPED:
1160 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1161 client_stop(client, r);
1166 static int client_receive_message_udp(sd_event_source *s, int fd,
1167 uint32_t revents, void *userdata) {
1168 sd_dhcp_client *client = userdata;
1169 _cleanup_free_ DHCPMessage *message = NULL;
1170 int buflen = 0, len, r;
1175 r = ioctl(fd, FIONREAD, &buflen);
1176 if (r < 0 || buflen <= 0)
1177 buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE;
1179 message = malloc0(buflen);
1183 len = read(fd, message, buflen);
1185 log_dhcp_client(client, "could not receive message from UDP "
1186 "socket: %s", strerror(errno));
1188 } else if ((size_t)len < sizeof(DHCPMessage))
1191 return client_handle_message(client, message, len);
1194 static int client_receive_message_raw(sd_event_source *s, int fd,
1195 uint32_t revents, void *userdata) {
1196 sd_dhcp_client *client = userdata;
1197 _cleanup_free_ DHCPPacket *packet = NULL;
1198 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1199 struct iovec iov = {};
1200 struct msghdr msg = {
1203 .msg_control = cmsgbuf,
1204 .msg_controllen = sizeof(cmsgbuf),
1206 struct cmsghdr *cmsg;
1207 bool checksum = true;
1208 int buflen = 0, len, r;
1213 r = ioctl(fd, FIONREAD, &buflen);
1214 if (r < 0 || buflen <= 0)
1215 buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE;
1217 packet = malloc0(buflen);
1221 iov.iov_base = packet;
1222 iov.iov_len = buflen;
1224 len = recvmsg(fd, &msg, 0);
1226 log_dhcp_client(client, "could not receive message from raw "
1227 "socket: %s", strerror(errno));
1229 } else if ((size_t)len < sizeof(DHCPPacket))
1232 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1233 if (cmsg->cmsg_level == SOL_PACKET &&
1234 cmsg->cmsg_type == PACKET_AUXDATA &&
1235 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1236 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1238 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1243 r = dhcp_packet_verify_headers(packet, len, checksum);
1247 len -= DHCP_IP_UDP_SIZE;
1249 return client_handle_message(client, &packet->dhcp, len);
1252 int sd_dhcp_client_start(sd_dhcp_client *client) {
1255 assert_return(client, -EINVAL);
1257 r = client_initialize(client);
1261 if (client->last_addr)
1262 client->state = DHCP_STATE_INIT_REBOOT;
1264 r = client_start(client);
1266 log_dhcp_client(client, "STARTED");
1271 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1272 assert_return(client, -EINVAL);
1274 if (client_stop(client, DHCP_EVENT_STOP))
1275 client->state = DHCP_STATE_STOPPED;
1280 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1284 assert_return(client, -EINVAL);
1285 assert_return(!client->event, -EBUSY);
1288 client->event = sd_event_ref(event);
1290 r = sd_event_default(&client->event);
1295 client->event_priority = priority;
1300 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1301 assert_return(client, -EINVAL);
1303 client->event = sd_event_unref(client->event);
1308 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1312 return client->event;
1315 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1317 assert_se(REFCNT_INC(client->n_ref) >= 2);
1322 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1323 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1324 log_dhcp_client(client, "UNREF");
1326 client_initialize(client);
1328 client->receive_message =
1329 sd_event_source_unref(client->receive_message);
1331 sd_dhcp_client_detach_event(client);
1333 free(client->req_opts);
1342 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
1343 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1345 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1346 _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1348 assert_return(ret, -EINVAL);
1350 client = new0(sd_dhcp_client, 1);
1354 client->n_ref = REFCNT_INIT;
1355 client->state = DHCP_STATE_INIT;
1358 client->attempt = 1;
1360 client->req_opts_size = ELEMENTSOF(default_req_opts);
1362 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1363 if (!client->req_opts)