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 void 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 DHCP_CLIENT_DONT_DESTROY(client);
157 bool need_restart = false;
159 assert_return(client, -EINVAL);
160 assert_return(addr, -EINVAL);
162 if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
165 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
166 log_dhcp_client(client, "Changing MAC address on running DHCP "
167 "client, restarting");
169 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 void client_notify(sd_dhcp_client *client, int event) {
197 client->cb(client, event, client->userdata);
200 static int client_initialize(sd_dhcp_client *client) {
201 assert_return(client, -EINVAL);
203 client->receive_message =
204 sd_event_source_unref(client->receive_message);
206 client->fd = asynchronous_close(client->fd);
208 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
210 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
211 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
212 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
216 client->state = DHCP_STATE_INIT;
220 client->lease = sd_dhcp_lease_unref(client->lease);
225 static void client_stop(sd_dhcp_client *client, int error) {
229 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
232 case DHCP_EVENT_STOP:
233 log_dhcp_client(client, "STOPPED");
235 case DHCP_EVENT_NO_LEASE:
236 log_dhcp_client(client, "STOPPED: No lease");
239 log_dhcp_client(client, "STOPPED: Unknown reason");
244 client_notify(client, error);
246 client_initialize(client);
249 static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
250 uint8_t type, size_t *_optlen, size_t *_optoffset) {
251 _cleanup_free_ DHCPPacket *packet;
252 size_t optlen, optoffset, size;
257 assert(client->secs);
261 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
263 optlen = DHCP_MIN_OPTIONS_SIZE;
264 size = sizeof(DHCPPacket) + optlen;
266 packet = malloc0(size);
270 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
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 packet->dhcp.secs = htobe16(client->secs);
279 /* RFC2132 section 4.1
280 A client that cannot receive unicast IP datagrams until its protocol
281 software has been configured with an IP address SHOULD set the
282 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
283 DHCPREQUEST messages that client sends. The BROADCAST bit will
284 provide a hint to the DHCP server and BOOTP relay agent to broadcast
285 any messages to the client on the client's subnet. */
286 packet->dhcp.flags = htobe16(0x8000);
288 /* RFC2132 section 4.1.1:
289 The client MUST include its hardware address in the ’chaddr’ field, if
290 necessary for delivery of DHCP reply messages.
292 memcpy(&packet->dhcp.chaddr, &client->client_id.mac_addr, ETH_ALEN);
294 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
295 Identifier option is not set */
296 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
297 DHCP_OPTION_CLIENT_IDENTIFIER,
298 sizeof(client->client_id), &client->client_id);
303 /* RFC2131 section 3.5:
304 in its initial DHCPDISCOVER or DHCPREQUEST message, a
305 client may provide the server with a list of specific
306 parameters the client is interested in. If the client
307 includes a list of parameters in a DHCPDISCOVER message,
308 it MUST include that list in any subsequent DHCPREQUEST
311 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
312 DHCP_OPTION_PARAMETER_REQUEST_LIST,
313 client->req_opts_size, client->req_opts);
317 /* RFC2131 section 3.5:
318 The client SHOULD include the ’maximum DHCP message size’ option to
319 let the server know how large the server may make its DHCP messages.
321 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
322 than the defined default size unless the Maximum Messge Size option
325 max_size = htobe16(size);
326 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
327 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
333 *_optoffset = optoffset;
340 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
342 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
343 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
345 return dhcp_network_send_raw_socket(client->fd, &client->link,
349 static int client_send_discover(sd_dhcp_client *client) {
350 _cleanup_free_ DHCPPacket *discover = NULL;
351 size_t optoffset, optlen;
356 assert(client->state == DHCP_STATE_INIT ||
357 client->state == DHCP_STATE_SELECTING);
359 /* See RFC2131 section 4.4.1 */
361 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
364 assert(time_now >= client->start_time);
366 /* seconds between sending first and last DISCOVER
367 * must always be strictly positive to deal with broken servers */
368 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
370 r = client_message_init(client, &discover, DHCP_DISCOVER,
371 &optlen, &optoffset);
375 /* the client may suggest values for the network address
376 and lease time in the DHCPDISCOVER message. The client may include
377 the ’requested IP address’ option to suggest that a particular IP
378 address be assigned, and may include the ’IP address lease time’
379 option to suggest the lease time it would like.
381 if (client->last_addr != INADDR_ANY) {
382 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
383 DHCP_OPTION_REQUESTED_IP_ADDRESS,
384 4, &client->last_addr);
389 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
390 DHCP_OPTION_END, 0, NULL);
394 /* We currently ignore:
395 The client SHOULD wait a random time between one and ten seconds to
396 desynchronize the use of DHCP at startup.
398 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
402 log_dhcp_client(client, "DISCOVER");
407 static int client_send_request(sd_dhcp_client *client) {
408 _cleanup_free_ DHCPPacket *request = NULL;
409 size_t optoffset, optlen;
412 r = client_message_init(client, &request, DHCP_REQUEST,
413 &optlen, &optoffset);
417 switch (client->state) {
418 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
419 SELECTING should be REQUESTING)
422 case DHCP_STATE_REQUESTING:
423 /* Client inserts the address of the selected server in ’server
424 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
425 filled in with the yiaddr value from the chosen DHCPOFFER.
428 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
429 DHCP_OPTION_SERVER_IDENTIFIER,
430 4, &client->lease->server_address);
434 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
435 DHCP_OPTION_REQUESTED_IP_ADDRESS,
436 4, &client->lease->address);
442 case DHCP_STATE_INIT_REBOOT:
443 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
444 option MUST be filled in with client’s notion of its previously
445 assigned address. ’ciaddr’ MUST be zero.
447 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
448 DHCP_OPTION_REQUESTED_IP_ADDRESS,
449 4, &client->last_addr);
454 case DHCP_STATE_RENEWING:
455 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
456 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
457 client’s IP address.
461 case DHCP_STATE_REBINDING:
462 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
463 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
464 client’s IP address.
466 This message MUST be broadcast to the 0xffffffff IP broadcast address.
468 request->dhcp.ciaddr = client->lease->address;
472 case DHCP_STATE_INIT:
473 case DHCP_STATE_SELECTING:
474 case DHCP_STATE_REBOOTING:
475 case DHCP_STATE_BOUND:
476 case DHCP_STATE_STOPPED:
480 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
481 DHCP_OPTION_END, 0, NULL);
485 if (client->state == DHCP_STATE_RENEWING) {
486 r = dhcp_network_send_udp_socket(client->fd,
487 client->lease->server_address,
490 sizeof(DHCPMessage) + optoffset);
492 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
497 switch (client->state) {
498 case DHCP_STATE_REQUESTING:
499 log_dhcp_client(client, "REQUEST (requesting)");
501 case DHCP_STATE_INIT_REBOOT:
502 log_dhcp_client(client, "REQUEST (init-reboot)");
504 case DHCP_STATE_RENEWING:
505 log_dhcp_client(client, "REQUEST (renewing)");
507 case DHCP_STATE_REBINDING:
508 log_dhcp_client(client, "REQUEST (rebinding)");
511 log_dhcp_client(client, "REQUEST (invalid)");
518 static int client_start(sd_dhcp_client *client);
520 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
522 sd_dhcp_client *client = userdata;
523 DHCP_CLIENT_DONT_DESTROY(client);
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;
731 DHCP_CLIENT_DONT_DESTROY(client);
733 log_dhcp_client(client, "EXPIRED");
735 client_notify(client, DHCP_EVENT_EXPIRED);
737 /* lease was lost, start over if not freed or stopped in callback */
738 if (client->state != DHCP_STATE_STOPPED) {
739 client_initialize(client);
740 client_start(client);
746 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
747 sd_dhcp_client *client = userdata;
748 DHCP_CLIENT_DONT_DESTROY(client);
751 client->receive_message = sd_event_source_unref(client->receive_message);
752 client->fd = asynchronous_close(client->fd);
754 client->state = DHCP_STATE_REBINDING;
757 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
759 client_stop(client, r);
764 return client_initialize_events(client, client_receive_message_raw);
767 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
769 sd_dhcp_client *client = userdata;
770 DHCP_CLIENT_DONT_DESTROY(client);
773 client->state = DHCP_STATE_RENEWING;
776 r = dhcp_network_bind_udp_socket(client->lease->address,
779 client_stop(client, r);
785 return client_initialize_events(client, client_receive_message_udp);
788 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
790 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
793 r = dhcp_lease_new(&lease);
797 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
798 if (r != DHCP_OFFER) {
799 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
803 lease->next_server = offer->siaddr;
805 lease->address = offer->yiaddr;
807 if (lease->address == INADDR_ANY ||
808 lease->server_address == INADDR_ANY ||
809 lease->lifetime == 0) {
810 log_dhcp_client(client, "receieved lease lacks address, server "
811 "address or lease lifetime, ignoring");
815 if (lease->subnet_mask == INADDR_ANY) {
816 r = dhcp_lease_set_default_subnet_mask(lease);
818 log_dhcp_client(client, "receieved lease lacks subnet "
819 "mask, and a fallback one can not be "
820 "generated, ignoring");
825 sd_dhcp_lease_unref(client->lease);
826 client->lease = lease;
829 log_dhcp_client(client, "OFFER");
834 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
836 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
839 r = dhcp_lease_new(&lease);
843 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
845 log_dhcp_client(client, "NAK");
846 return DHCP_EVENT_NO_LEASE;
850 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
854 lease->next_server = ack->siaddr;
856 lease->address = ack->yiaddr;
858 if (lease->address == INADDR_ANY ||
859 lease->server_address == INADDR_ANY ||
860 lease->lifetime == 0) {
861 log_dhcp_client(client, "receieved lease lacks address, server "
862 "address or lease lifetime, ignoring");
866 if (lease->subnet_mask == INADDR_ANY) {
867 r = dhcp_lease_set_default_subnet_mask(lease);
869 log_dhcp_client(client, "receieved lease lacks subnet "
870 "mask, and a fallback one can not be "
871 "generated, ignoring");
876 r = DHCP_EVENT_IP_ACQUIRE;
878 if (client->lease->address != lease->address ||
879 client->lease->subnet_mask != lease->subnet_mask ||
880 client->lease->router != lease->router) {
881 r = DHCP_EVENT_IP_CHANGE;
884 client->lease = sd_dhcp_lease_unref(client->lease);
887 client->lease = lease;
890 log_dhcp_client(client, "ACK");
895 static uint64_t client_compute_timeout(sd_dhcp_client *client,
896 uint32_t lifetime, double factor) {
898 assert(client->request_sent);
901 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
902 + (random_u32() & 0x1fffff);
905 static int client_set_lease_timeouts(sd_dhcp_client *client) {
907 uint64_t lifetime_timeout;
910 char time_string[FORMAT_TIMESPAN_MAX];
914 assert(client->event);
915 assert(client->lease);
916 assert(client->lease->lifetime);
918 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
919 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
920 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
922 /* don't set timers for infinite leases */
923 if (client->lease->lifetime == 0xffffffff)
926 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
929 assert(client->request_sent <= time_now);
931 /* convert the various timeouts from relative (secs) to absolute (usecs) */
932 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
933 if (client->lease->t1 && client->lease->t2) {
934 /* both T1 and T2 are given */
935 if (client->lease->t1 < client->lease->t2 &&
936 client->lease->t2 < client->lease->lifetime) {
937 /* they are both valid */
938 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
939 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 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
945 client->lease->t1 = client->lease->lifetime / 2;
947 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
948 /* only T2 is given, and it is valid */
949 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
950 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
951 client->lease->t1 = client->lease->lifetime / 2;
952 if (t2_timeout <= t1_timeout) {
953 /* the computed T1 would be invalid, so discard T2 */
954 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
955 client->lease->t2 = (client->lease->lifetime * 7) / 8;
957 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
958 /* only T1 is given, and it is valid */
959 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
960 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
961 client->lease->t2 = (client->lease->lifetime * 7) / 8;
962 if (t2_timeout <= t1_timeout) {
963 /* the computed T2 would be invalid, so discard T1 */
964 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
965 client->lease->t2 = client->lease->lifetime / 2;
968 /* fall back to the default timeouts */
969 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
970 client->lease->t1 = client->lease->lifetime / 2;
971 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
972 client->lease->t2 = (client->lease->lifetime * 7) / 8;
975 /* arm lifetime timeout */
976 r = sd_event_add_time(client->event, &client->timeout_expire,
978 lifetime_timeout, 10 * USEC_PER_MSEC,
979 client_timeout_expire, client);
983 r = sd_event_source_set_priority(client->timeout_expire,
984 client->event_priority);
988 log_dhcp_client(client, "lease expires in %s",
989 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
990 lifetime_timeout - time_now, 0));
992 /* don't arm earlier timeouts if this has already expired */
993 if (lifetime_timeout <= time_now)
997 r = sd_event_add_time(client->event,
1002 client_timeout_t2, client);
1006 r = sd_event_source_set_priority(client->timeout_t2,
1007 client->event_priority);
1011 log_dhcp_client(client, "T2 expires in %s",
1012 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1013 t2_timeout - time_now, 0));
1015 /* don't arm earlier timeout if this has already expired */
1016 if (t2_timeout <= time_now)
1019 /* arm T1 timeout */
1020 r = sd_event_add_time(client->event,
1021 &client->timeout_t1,
1023 t1_timeout, 10 * USEC_PER_MSEC,
1024 client_timeout_t1, client);
1028 r = sd_event_source_set_priority(client->timeout_t1,
1029 client->event_priority);
1033 log_dhcp_client(client, "T1 expires in %s",
1034 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1035 t1_timeout - time_now, 0));
1040 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1042 DHCP_CLIENT_DONT_DESTROY(client);
1043 int r = 0, notify_event = 0;
1046 assert(client->event);
1049 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1050 log_dhcp_client(client, "not a DHCP message: ignoring");
1054 if (message->op != BOOTREPLY) {
1055 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1059 if (be32toh(message->xid) != client->xid) {
1060 log_dhcp_client(client, "received xid (%u) does not match "
1061 "expected (%u): ignoring",
1062 be32toh(message->xid), client->xid);
1066 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1067 log_dhcp_client(client, "not an ethernet packet");
1071 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1073 log_dhcp_client(client, "received chaddr does not match "
1074 "expected: ignoring");
1078 switch (client->state) {
1079 case DHCP_STATE_SELECTING:
1081 r = client_handle_offer(client, message, len);
1084 client->timeout_resend =
1085 sd_event_source_unref(client->timeout_resend);
1087 client->state = DHCP_STATE_REQUESTING;
1088 client->attempt = 1;
1090 r = sd_event_add_time(client->event,
1091 &client->timeout_resend,
1094 client_timeout_resend, client);
1098 r = sd_event_source_set_priority(client->timeout_resend,
1099 client->event_priority);
1102 } else if (r == -ENOMSG)
1103 /* invalid message, let's ignore it */
1108 case DHCP_STATE_REBOOTING:
1109 case DHCP_STATE_REQUESTING:
1110 case DHCP_STATE_RENEWING:
1111 case DHCP_STATE_REBINDING:
1113 r = client_handle_ack(client, message, len);
1114 if (r == DHCP_EVENT_NO_LEASE) {
1116 client->timeout_resend =
1117 sd_event_source_unref(client->timeout_resend);
1119 if (client->state == DHCP_STATE_REBOOTING) {
1120 r = client_initialize(client);
1124 r = client_start(client);
1128 log_dhcp_client(client, "REBOOTED");
1132 } else if (r >= 0) {
1133 client->timeout_resend =
1134 sd_event_source_unref(client->timeout_resend);
1136 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1137 DHCP_STATE_REBOOTING))
1138 notify_event = DHCP_EVENT_IP_ACQUIRE;
1139 else if (r != DHCP_EVENT_IP_ACQUIRE)
1142 client->state = DHCP_STATE_BOUND;
1143 client->attempt = 1;
1145 client->last_addr = client->lease->address;
1147 r = client_set_lease_timeouts(client);
1152 client_notify(client, notify_event);
1153 if (client->state == DHCP_STATE_STOPPED)
1157 client->receive_message =
1158 sd_event_source_unref(client->receive_message);
1159 client->fd = asynchronous_close(client->fd);
1160 } else if (r == -ENOMSG)
1161 /* invalid message, let's ignore it */
1166 case DHCP_STATE_INIT:
1167 case DHCP_STATE_INIT_REBOOT:
1168 case DHCP_STATE_BOUND:
1172 case DHCP_STATE_STOPPED:
1178 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1179 client_stop(client, r);
1184 static int client_receive_message_udp(sd_event_source *s, int fd,
1185 uint32_t revents, void *userdata) {
1186 sd_dhcp_client *client = userdata;
1187 _cleanup_free_ DHCPMessage *message = NULL;
1188 int buflen = 0, len, r;
1193 r = ioctl(fd, FIONREAD, &buflen);
1198 /* this can't be right */
1201 message = malloc0(buflen);
1205 len = read(fd, message, buflen);
1207 log_dhcp_client(client, "could not receive message from UDP "
1210 } else if ((size_t)len < sizeof(DHCPMessage))
1213 return client_handle_message(client, message, len);
1216 static int client_receive_message_raw(sd_event_source *s, int fd,
1217 uint32_t revents, void *userdata) {
1218 sd_dhcp_client *client = userdata;
1219 _cleanup_free_ DHCPPacket *packet = NULL;
1220 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1221 struct iovec iov = {};
1222 struct msghdr msg = {
1225 .msg_control = cmsgbuf,
1226 .msg_controllen = sizeof(cmsgbuf),
1228 struct cmsghdr *cmsg;
1229 bool checksum = true;
1230 int buflen = 0, len, r;
1235 r = ioctl(fd, FIONREAD, &buflen);
1240 /* this can't be right */
1243 packet = malloc0(buflen);
1247 iov.iov_base = packet;
1248 iov.iov_len = buflen;
1250 len = recvmsg(fd, &msg, 0);
1252 log_dhcp_client(client, "could not receive message from raw "
1255 } else if ((size_t)len < sizeof(DHCPPacket))
1258 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1259 if (cmsg->cmsg_level == SOL_PACKET &&
1260 cmsg->cmsg_type == PACKET_AUXDATA &&
1261 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1262 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1264 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1269 r = dhcp_packet_verify_headers(packet, len, checksum);
1273 len -= DHCP_IP_UDP_SIZE;
1275 return client_handle_message(client, &packet->dhcp, len);
1278 int sd_dhcp_client_start(sd_dhcp_client *client) {
1281 assert_return(client, -EINVAL);
1283 r = client_initialize(client);
1287 if (client->last_addr)
1288 client->state = DHCP_STATE_INIT_REBOOT;
1290 r = client_start(client);
1292 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1294 ether_ntoa(&client->client_id.mac_addr));
1299 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1300 DHCP_CLIENT_DONT_DESTROY(client);
1302 assert_return(client, -EINVAL);
1304 client_stop(client, DHCP_EVENT_STOP);
1305 client->state = DHCP_STATE_STOPPED;
1310 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1314 assert_return(client, -EINVAL);
1315 assert_return(!client->event, -EBUSY);
1318 client->event = sd_event_ref(event);
1320 r = sd_event_default(&client->event);
1325 client->event_priority = priority;
1330 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1331 assert_return(client, -EINVAL);
1333 client->event = sd_event_unref(client->event);
1338 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1342 return client->event;
1345 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1347 assert_se(REFCNT_INC(client->n_ref) >= 2);
1352 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1353 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1354 log_dhcp_client(client, "FREE");
1356 client_initialize(client);
1358 client->receive_message =
1359 sd_event_source_unref(client->receive_message);
1361 sd_dhcp_client_detach_event(client);
1363 sd_dhcp_lease_unref(client->lease);
1365 free(client->req_opts);
1372 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1373 _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1375 assert_return(ret, -EINVAL);
1377 client = new0(sd_dhcp_client, 1);
1381 client->n_ref = REFCNT_INIT;
1382 client->state = DHCP_STATE_INIT;
1385 client->attempt = 1;
1387 client->req_opts_size = ELEMENTSOF(default_req_opts);
1389 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1390 if (!client->req_opts)