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;
51 bool request_broadcast;
53 size_t req_opts_allocated;
58 struct ether_addr mac_addr;
61 char *vendor_class_identifier;
67 sd_event_source *timeout_t1;
68 sd_event_source *timeout_t2;
69 sd_event_source *timeout_expire;
70 sd_dhcp_client_cb_t cb;
75 static const uint8_t default_req_opts[] = {
76 DHCP_OPTION_SUBNET_MASK,
78 DHCP_OPTION_HOST_NAME,
79 DHCP_OPTION_DOMAIN_NAME,
80 DHCP_OPTION_DOMAIN_NAME_SERVER,
81 DHCP_OPTION_NTP_SERVER,
84 static int client_receive_message_raw(sd_event_source *s, int fd,
85 uint32_t revents, void *userdata);
86 static int client_receive_message_udp(sd_event_source *s, int fd,
87 uint32_t revents, void *userdata);
88 static void client_stop(sd_dhcp_client *client, int error);
90 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
92 assert_return(client, -EINVAL);
95 client->userdata = userdata;
100 int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
101 assert_return(client, -EINVAL);
103 client->request_broadcast = !!broadcast;
108 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
111 assert_return(client, -EINVAL);
112 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
113 DHCP_STATE_STOPPED), -EBUSY);
116 case DHCP_OPTION_PAD:
117 case DHCP_OPTION_OVERLOAD:
118 case DHCP_OPTION_MESSAGE_TYPE:
119 case DHCP_OPTION_PARAMETER_REQUEST_LIST:
120 case DHCP_OPTION_END:
127 for (i = 0; i < client->req_opts_size; i++)
128 if (client->req_opts[i] == option)
131 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
132 client->req_opts_size + 1))
135 client->req_opts[client->req_opts_size++] = option;
140 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
141 const struct in_addr *last_addr) {
142 assert_return(client, -EINVAL);
143 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
144 DHCP_STATE_STOPPED), -EBUSY);
147 client->last_addr = last_addr->s_addr;
149 client->last_addr = INADDR_ANY;
154 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
155 assert_return(client, -EINVAL);
156 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
157 DHCP_STATE_STOPPED), -EBUSY);
158 assert_return(interface_index > 0, -EINVAL);
160 client->index = interface_index;
165 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
166 const struct ether_addr *addr) {
167 DHCP_CLIENT_DONT_DESTROY(client);
168 bool need_restart = false;
170 assert_return(client, -EINVAL);
171 assert_return(addr, -EINVAL);
173 if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
176 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
177 log_dhcp_client(client, "Changing MAC address on running DHCP "
178 "client, restarting");
180 client_stop(client, DHCP_EVENT_STOP);
183 memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
184 client->client_id.type = 0x01;
186 if (need_restart && client->state != DHCP_STATE_STOPPED)
187 sd_dhcp_client_start(client);
192 int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
193 const char *hostname) {
194 char *new_hostname = NULL;
196 assert_return(client, -EINVAL);
198 if (streq_ptr(client->hostname, hostname))
202 new_hostname = strdup(hostname);
207 free(client->hostname);
208 client->hostname = new_hostname;
213 int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client,
215 char *new_vci = NULL;
217 assert_return(client, -EINVAL);
219 new_vci = strdup(vci);
223 free(client->vendor_class_identifier);
225 client->vendor_class_identifier = new_vci;
230 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
231 assert_return(client, -EINVAL);
232 assert_return(ret, -EINVAL);
234 if (client->state != DHCP_STATE_BOUND &&
235 client->state != DHCP_STATE_RENEWING &&
236 client->state != DHCP_STATE_REBINDING)
237 return -EADDRNOTAVAIL;
239 *ret = sd_dhcp_lease_ref(client->lease);
244 static void client_notify(sd_dhcp_client *client, int event) {
246 client->cb(client, event, client->userdata);
249 static int client_initialize(sd_dhcp_client *client) {
250 assert_return(client, -EINVAL);
252 client->receive_message =
253 sd_event_source_unref(client->receive_message);
255 client->fd = asynchronous_close(client->fd);
257 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
259 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
260 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
261 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
265 client->state = DHCP_STATE_INIT;
269 client->lease = sd_dhcp_lease_unref(client->lease);
274 static void client_stop(sd_dhcp_client *client, int error) {
278 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
281 case DHCP_EVENT_STOP:
282 log_dhcp_client(client, "STOPPED");
284 case DHCP_EVENT_NO_LEASE:
285 log_dhcp_client(client, "STOPPED: No lease");
288 log_dhcp_client(client, "STOPPED: Unknown reason");
293 client_notify(client, error);
295 client_initialize(client);
298 static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
299 uint8_t type, size_t *_optlen, size_t *_optoffset) {
300 _cleanup_free_ DHCPPacket *packet;
301 size_t optlen, optoffset, size;
306 assert(client->secs);
310 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
312 optlen = DHCP_MIN_OPTIONS_SIZE;
313 size = sizeof(DHCPPacket) + optlen;
315 packet = malloc0(size);
319 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
324 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
325 refuse to issue an DHCP lease if 'secs' is set to zero */
326 packet->dhcp.secs = htobe16(client->secs);
328 /* RFC2132 section 4.1
329 A client that cannot receive unicast IP datagrams until its protocol
330 software has been configured with an IP address SHOULD set the
331 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
332 DHCPREQUEST messages that client sends. The BROADCAST bit will
333 provide a hint to the DHCP server and BOOTP relay agent to broadcast
334 any messages to the client on the client's subnet.
336 Note: some interfaces needs this to be enabled, but some networks
337 needs this to be disabled as broadcasts are filteretd, so this
338 needs to be configurable */
339 if (client->request_broadcast)
340 packet->dhcp.flags = htobe16(0x8000);
342 /* RFC2132 section 4.1.1:
343 The client MUST include its hardware address in the ’chaddr’ field, if
344 necessary for delivery of DHCP reply messages.
346 memcpy(&packet->dhcp.chaddr, &client->client_id.mac_addr, ETH_ALEN);
348 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
349 Identifier option is not set */
350 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
351 DHCP_OPTION_CLIENT_IDENTIFIER,
352 sizeof(client->client_id), &client->client_id);
357 /* RFC2131 section 3.5:
358 in its initial DHCPDISCOVER or DHCPREQUEST message, a
359 client may provide the server with a list of specific
360 parameters the client is interested in. If the client
361 includes a list of parameters in a DHCPDISCOVER message,
362 it MUST include that list in any subsequent DHCPREQUEST
365 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
366 DHCP_OPTION_PARAMETER_REQUEST_LIST,
367 client->req_opts_size, client->req_opts);
371 /* RFC2131 section 3.5:
372 The client SHOULD include the ’maximum DHCP message size’ option to
373 let the server know how large the server may make its DHCP messages.
375 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
376 than the defined default size unless the Maximum Messge Size option
379 max_size = htobe16(size);
380 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
381 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
387 *_optoffset = optoffset;
394 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
396 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
397 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
399 return dhcp_network_send_raw_socket(client->fd, &client->link,
403 static int client_send_discover(sd_dhcp_client *client) {
404 _cleanup_free_ DHCPPacket *discover = NULL;
405 size_t optoffset, optlen;
410 assert(client->state == DHCP_STATE_INIT ||
411 client->state == DHCP_STATE_SELECTING);
413 /* See RFC2131 section 4.4.1 */
415 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
418 assert(time_now >= client->start_time);
420 /* seconds between sending first and last DISCOVER
421 * must always be strictly positive to deal with broken servers */
422 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
424 r = client_message_init(client, &discover, DHCP_DISCOVER,
425 &optlen, &optoffset);
429 /* the client may suggest values for the network address
430 and lease time in the DHCPDISCOVER message. The client may include
431 the ’requested IP address’ option to suggest that a particular IP
432 address be assigned, and may include the ’IP address lease time’
433 option to suggest the lease time it would like.
435 if (client->last_addr != INADDR_ANY) {
436 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
437 DHCP_OPTION_REQUESTED_IP_ADDRESS,
438 4, &client->last_addr);
443 /* it is unclear from RFC 2131 if client should send hostname in
444 DHCPDISCOVER but dhclient does and so we do as well
446 if (client->hostname) {
447 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
448 DHCP_OPTION_HOST_NAME,
449 strlen(client->hostname), client->hostname);
454 if (client->vendor_class_identifier) {
455 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
456 DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
457 strlen(client->vendor_class_identifier),
458 client->vendor_class_identifier);
463 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
464 DHCP_OPTION_END, 0, NULL);
468 /* We currently ignore:
469 The client SHOULD wait a random time between one and ten seconds to
470 desynchronize the use of DHCP at startup.
472 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
476 log_dhcp_client(client, "DISCOVER");
481 static int client_send_request(sd_dhcp_client *client) {
482 _cleanup_free_ DHCPPacket *request = NULL;
483 size_t optoffset, optlen;
486 r = client_message_init(client, &request, DHCP_REQUEST,
487 &optlen, &optoffset);
491 switch (client->state) {
492 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
493 SELECTING should be REQUESTING)
496 case DHCP_STATE_REQUESTING:
497 /* Client inserts the address of the selected server in ’server
498 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
499 filled in with the yiaddr value from the chosen DHCPOFFER.
502 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
503 DHCP_OPTION_SERVER_IDENTIFIER,
504 4, &client->lease->server_address);
508 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
509 DHCP_OPTION_REQUESTED_IP_ADDRESS,
510 4, &client->lease->address);
516 case DHCP_STATE_INIT_REBOOT:
517 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
518 option MUST be filled in with client’s notion of its previously
519 assigned address. ’ciaddr’ MUST be zero.
521 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
522 DHCP_OPTION_REQUESTED_IP_ADDRESS,
523 4, &client->last_addr);
528 case DHCP_STATE_RENEWING:
529 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
530 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
531 client’s IP address.
535 case DHCP_STATE_REBINDING:
536 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
537 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
538 client’s IP address.
540 This message MUST be broadcast to the 0xffffffff IP broadcast address.
542 request->dhcp.ciaddr = client->lease->address;
546 case DHCP_STATE_INIT:
547 case DHCP_STATE_SELECTING:
548 case DHCP_STATE_REBOOTING:
549 case DHCP_STATE_BOUND:
550 case DHCP_STATE_STOPPED:
554 if (client->hostname) {
555 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
556 DHCP_OPTION_HOST_NAME,
557 strlen(client->hostname), client->hostname);
562 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
563 DHCP_OPTION_END, 0, NULL);
567 if (client->state == DHCP_STATE_RENEWING) {
568 r = dhcp_network_send_udp_socket(client->fd,
569 client->lease->server_address,
572 sizeof(DHCPMessage) + optoffset);
574 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
579 switch (client->state) {
580 case DHCP_STATE_REQUESTING:
581 log_dhcp_client(client, "REQUEST (requesting)");
583 case DHCP_STATE_INIT_REBOOT:
584 log_dhcp_client(client, "REQUEST (init-reboot)");
586 case DHCP_STATE_RENEWING:
587 log_dhcp_client(client, "REQUEST (renewing)");
589 case DHCP_STATE_REBINDING:
590 log_dhcp_client(client, "REQUEST (rebinding)");
593 log_dhcp_client(client, "REQUEST (invalid)");
600 static int client_start(sd_dhcp_client *client);
602 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
604 sd_dhcp_client *client = userdata;
605 DHCP_CLIENT_DONT_DESTROY(client);
606 usec_t next_timeout = 0;
613 assert(client->event);
615 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
619 switch (client->state) {
620 case DHCP_STATE_RENEWING:
622 time_left = (client->lease->t2 - client->lease->t1) / 2;
626 next_timeout = time_now + time_left * USEC_PER_SEC;
630 case DHCP_STATE_REBINDING:
632 time_left = (client->lease->lifetime - client->lease->t2) / 2;
636 next_timeout = time_now + time_left * USEC_PER_SEC;
639 case DHCP_STATE_REBOOTING:
640 /* start over as we did not receive a timely ack or nak */
641 r = client_initialize(client);
645 r = client_start(client);
649 log_dhcp_client(client, "REBOOTED");
653 case DHCP_STATE_INIT:
654 case DHCP_STATE_INIT_REBOOT:
655 case DHCP_STATE_SELECTING:
656 case DHCP_STATE_REQUESTING:
657 case DHCP_STATE_BOUND:
659 if (client->attempt < 64)
660 client->attempt *= 2;
662 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
666 case DHCP_STATE_STOPPED:
671 next_timeout += (random_u32() & 0x1fffff);
673 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
675 r = sd_event_add_time(client->event,
676 &client->timeout_resend,
677 clock_boottime_or_monotonic(),
678 next_timeout, 10 * USEC_PER_MSEC,
679 client_timeout_resend, client);
683 r = sd_event_source_set_priority(client->timeout_resend,
684 client->event_priority);
688 switch (client->state) {
689 case DHCP_STATE_INIT:
690 r = client_send_discover(client);
692 client->state = DHCP_STATE_SELECTING;
695 if (client->attempt >= 64)
701 case DHCP_STATE_SELECTING:
702 r = client_send_discover(client);
703 if (r < 0 && client->attempt >= 64)
708 case DHCP_STATE_INIT_REBOOT:
709 case DHCP_STATE_REQUESTING:
710 case DHCP_STATE_RENEWING:
711 case DHCP_STATE_REBINDING:
712 r = client_send_request(client);
713 if (r < 0 && client->attempt >= 64)
716 if (client->state == DHCP_STATE_INIT_REBOOT)
717 client->state = DHCP_STATE_REBOOTING;
719 client->request_sent = time_now;
723 case DHCP_STATE_REBOOTING:
724 case DHCP_STATE_BOUND:
728 case DHCP_STATE_STOPPED:
736 client_stop(client, r);
738 /* Errors were dealt with when stopping the client, don't spill
739 errors into the event loop handler */
743 static int client_initialize_events(sd_dhcp_client *client,
744 sd_event_io_handler_t io_callback) {
748 assert(client->event);
750 r = sd_event_add_io(client->event, &client->receive_message,
751 client->fd, EPOLLIN, io_callback,
756 r = sd_event_source_set_priority(client->receive_message,
757 client->event_priority);
761 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
763 r = sd_event_add_time(client->event,
764 &client->timeout_resend,
765 clock_boottime_or_monotonic(),
767 client_timeout_resend, client);
771 r = sd_event_source_set_priority(client->timeout_resend,
772 client->event_priority);
776 client_stop(client, r);
782 static int client_start(sd_dhcp_client *client) {
785 assert_return(client, -EINVAL);
786 assert_return(client->event, -EINVAL);
787 assert_return(client->index > 0, -EINVAL);
788 assert_return(client->fd < 0, -EBUSY);
789 assert_return(client->xid == 0, -EINVAL);
790 assert_return(client->state == DHCP_STATE_INIT ||
791 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
793 client->xid = random_u32();
795 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
797 client_stop(client, r);
802 if (client->state == DHCP_STATE_INIT) {
803 client->start_time = now(clock_boottime_or_monotonic());
807 return client_initialize_events(client, client_receive_message_raw);
810 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
812 sd_dhcp_client *client = userdata;
813 DHCP_CLIENT_DONT_DESTROY(client);
815 log_dhcp_client(client, "EXPIRED");
817 client_notify(client, DHCP_EVENT_EXPIRED);
819 /* lease was lost, start over if not freed or stopped in callback */
820 if (client->state != DHCP_STATE_STOPPED) {
821 client_initialize(client);
822 client_start(client);
828 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
829 sd_dhcp_client *client = userdata;
830 DHCP_CLIENT_DONT_DESTROY(client);
833 client->receive_message = sd_event_source_unref(client->receive_message);
834 client->fd = asynchronous_close(client->fd);
836 client->state = DHCP_STATE_REBINDING;
839 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
841 client_stop(client, r);
846 return client_initialize_events(client, client_receive_message_raw);
849 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
851 sd_dhcp_client *client = userdata;
852 DHCP_CLIENT_DONT_DESTROY(client);
855 client->state = DHCP_STATE_RENEWING;
858 r = dhcp_network_bind_udp_socket(client->lease->address,
861 log_dhcp_client(client, "could not bind UDP socket");
867 return client_initialize_events(client, client_receive_message_udp);
870 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
872 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
875 r = dhcp_lease_new(&lease);
879 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
880 if (r != DHCP_OFFER) {
881 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
885 lease->next_server = offer->siaddr;
887 lease->address = offer->yiaddr;
889 if (lease->address == INADDR_ANY ||
890 lease->server_address == INADDR_ANY ||
891 lease->lifetime == 0) {
892 log_dhcp_client(client, "receieved lease lacks address, server "
893 "address or lease lifetime, ignoring");
897 if (lease->subnet_mask == INADDR_ANY) {
898 r = dhcp_lease_set_default_subnet_mask(lease);
900 log_dhcp_client(client, "receieved lease lacks subnet "
901 "mask, and a fallback one can not be "
902 "generated, ignoring");
907 sd_dhcp_lease_unref(client->lease);
908 client->lease = lease;
911 log_dhcp_client(client, "OFFER");
916 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
918 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
921 r = dhcp_lease_new(&lease);
925 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
927 log_dhcp_client(client, "NAK");
928 return DHCP_EVENT_NO_LEASE;
932 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
936 lease->next_server = ack->siaddr;
938 lease->address = ack->yiaddr;
940 if (lease->address == INADDR_ANY ||
941 lease->server_address == INADDR_ANY ||
942 lease->lifetime == 0) {
943 log_dhcp_client(client, "receieved lease lacks address, server "
944 "address or lease lifetime, ignoring");
948 if (lease->subnet_mask == INADDR_ANY) {
949 r = dhcp_lease_set_default_subnet_mask(lease);
951 log_dhcp_client(client, "receieved lease lacks subnet "
952 "mask, and a fallback one can not be "
953 "generated, ignoring");
958 r = DHCP_EVENT_IP_ACQUIRE;
960 if (client->lease->address != lease->address ||
961 client->lease->subnet_mask != lease->subnet_mask ||
962 client->lease->router != lease->router) {
963 r = DHCP_EVENT_IP_CHANGE;
965 r = DHCP_EVENT_RENEW;
967 client->lease = sd_dhcp_lease_unref(client->lease);
970 client->lease = lease;
973 log_dhcp_client(client, "ACK");
978 static uint64_t client_compute_timeout(sd_dhcp_client *client,
979 uint32_t lifetime, double factor) {
981 assert(client->request_sent);
984 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
985 + (random_u32() & 0x1fffff);
988 static int client_set_lease_timeouts(sd_dhcp_client *client) {
990 uint64_t lifetime_timeout;
993 char time_string[FORMAT_TIMESPAN_MAX];
997 assert(client->event);
998 assert(client->lease);
999 assert(client->lease->lifetime);
1001 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1002 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1003 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
1005 /* don't set timers for infinite leases */
1006 if (client->lease->lifetime == 0xffffffff)
1009 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1012 assert(client->request_sent <= time_now);
1014 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1015 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
1016 if (client->lease->t1 && client->lease->t2) {
1017 /* both T1 and T2 are given */
1018 if (client->lease->t1 < client->lease->t2 &&
1019 client->lease->t2 < client->lease->lifetime) {
1020 /* they are both valid */
1021 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1022 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1025 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1026 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1027 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1028 client->lease->t1 = client->lease->lifetime / 2;
1030 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
1031 /* only T2 is given, and it is valid */
1032 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1033 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1034 client->lease->t1 = client->lease->lifetime / 2;
1035 if (t2_timeout <= t1_timeout) {
1036 /* the computed T1 would be invalid, so discard T2 */
1037 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1038 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1040 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
1041 /* only T1 is given, and it is valid */
1042 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1043 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1044 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1045 if (t2_timeout <= t1_timeout) {
1046 /* the computed T2 would be invalid, so discard T1 */
1047 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1048 client->lease->t2 = client->lease->lifetime / 2;
1051 /* fall back to the default timeouts */
1052 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1053 client->lease->t1 = client->lease->lifetime / 2;
1054 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1055 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1058 /* arm lifetime timeout */
1059 r = sd_event_add_time(client->event, &client->timeout_expire,
1060 clock_boottime_or_monotonic(),
1061 lifetime_timeout, 10 * USEC_PER_MSEC,
1062 client_timeout_expire, client);
1066 r = sd_event_source_set_priority(client->timeout_expire,
1067 client->event_priority);
1071 log_dhcp_client(client, "lease expires in %s",
1072 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1073 lifetime_timeout - time_now, 0));
1075 /* don't arm earlier timeouts if this has already expired */
1076 if (lifetime_timeout <= time_now)
1079 /* arm T2 timeout */
1080 r = sd_event_add_time(client->event,
1081 &client->timeout_t2,
1082 clock_boottime_or_monotonic(),
1085 client_timeout_t2, client);
1089 r = sd_event_source_set_priority(client->timeout_t2,
1090 client->event_priority);
1094 log_dhcp_client(client, "T2 expires in %s",
1095 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1096 t2_timeout - time_now, 0));
1098 /* don't arm earlier timeout if this has already expired */
1099 if (t2_timeout <= time_now)
1102 /* arm T1 timeout */
1103 r = sd_event_add_time(client->event,
1104 &client->timeout_t1,
1105 clock_boottime_or_monotonic(),
1106 t1_timeout, 10 * USEC_PER_MSEC,
1107 client_timeout_t1, client);
1111 r = sd_event_source_set_priority(client->timeout_t1,
1112 client->event_priority);
1116 log_dhcp_client(client, "T1 expires in %s",
1117 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1118 t1_timeout - time_now, 0));
1123 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1125 DHCP_CLIENT_DONT_DESTROY(client);
1126 int r = 0, notify_event = 0;
1129 assert(client->event);
1132 switch (client->state) {
1133 case DHCP_STATE_SELECTING:
1135 r = client_handle_offer(client, message, len);
1138 client->timeout_resend =
1139 sd_event_source_unref(client->timeout_resend);
1141 client->state = DHCP_STATE_REQUESTING;
1142 client->attempt = 1;
1144 r = sd_event_add_time(client->event,
1145 &client->timeout_resend,
1146 clock_boottime_or_monotonic(),
1148 client_timeout_resend, client);
1152 r = sd_event_source_set_priority(client->timeout_resend,
1153 client->event_priority);
1156 } else if (r == -ENOMSG)
1157 /* invalid message, let's ignore it */
1162 case DHCP_STATE_REBOOTING:
1163 case DHCP_STATE_REQUESTING:
1164 case DHCP_STATE_RENEWING:
1165 case DHCP_STATE_REBINDING:
1167 r = client_handle_ack(client, message, len);
1168 if (r == DHCP_EVENT_NO_LEASE) {
1170 client->timeout_resend =
1171 sd_event_source_unref(client->timeout_resend);
1173 if (client->state == DHCP_STATE_REBOOTING) {
1174 r = client_initialize(client);
1178 r = client_start(client);
1182 log_dhcp_client(client, "REBOOTED");
1186 } else if (r >= 0) {
1187 client->timeout_resend =
1188 sd_event_source_unref(client->timeout_resend);
1190 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1191 DHCP_STATE_REBOOTING))
1192 notify_event = DHCP_EVENT_IP_ACQUIRE;
1193 else if (r != DHCP_EVENT_IP_ACQUIRE)
1196 client->state = DHCP_STATE_BOUND;
1197 client->attempt = 1;
1199 client->last_addr = client->lease->address;
1201 r = client_set_lease_timeouts(client);
1206 client_notify(client, notify_event);
1207 if (client->state == DHCP_STATE_STOPPED)
1211 client->receive_message =
1212 sd_event_source_unref(client->receive_message);
1213 client->fd = asynchronous_close(client->fd);
1214 } else if (r == -ENOMSG)
1215 /* invalid message, let's ignore it */
1220 case DHCP_STATE_INIT:
1221 case DHCP_STATE_INIT_REBOOT:
1222 case DHCP_STATE_BOUND:
1226 case DHCP_STATE_STOPPED:
1232 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1233 client_stop(client, r);
1238 static int client_receive_message_udp(sd_event_source *s, int fd,
1239 uint32_t revents, void *userdata) {
1240 sd_dhcp_client *client = userdata;
1241 _cleanup_free_ DHCPMessage *message = NULL;
1242 int buflen = 0, len, r;
1247 r = ioctl(fd, FIONREAD, &buflen);
1252 /* this can't be right */
1255 message = malloc0(buflen);
1259 len = read(fd, message, buflen);
1261 log_dhcp_client(client, "could not receive message from UDP "
1264 } else if ((size_t)len < sizeof(DHCPMessage)) {
1265 log_dhcp_client(client, "too small to be a DHCP message: ignoring");
1269 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1270 log_dhcp_client(client, "not a DHCP message: ignoring");
1274 if (message->op != BOOTREPLY) {
1275 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1279 if (be32toh(message->xid) != client->xid) {
1280 log_dhcp_client(client, "received xid (%u) does not match "
1281 "expected (%u): ignoring",
1282 be32toh(message->xid), client->xid);
1286 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1287 log_dhcp_client(client, "not an ethernet packet");
1291 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1293 log_dhcp_client(client, "received chaddr does not match "
1294 "expected: ignoring");
1298 return client_handle_message(client, message, len);
1301 static int client_receive_message_raw(sd_event_source *s, int fd,
1302 uint32_t revents, void *userdata) {
1303 sd_dhcp_client *client = userdata;
1304 _cleanup_free_ DHCPPacket *packet = NULL;
1305 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1306 struct iovec iov = {};
1307 struct msghdr msg = {
1310 .msg_control = cmsgbuf,
1311 .msg_controllen = sizeof(cmsgbuf),
1313 struct cmsghdr *cmsg;
1314 bool checksum = true;
1315 int buflen = 0, len, r;
1320 r = ioctl(fd, FIONREAD, &buflen);
1325 /* this can't be right */
1328 packet = malloc0(buflen);
1332 iov.iov_base = packet;
1333 iov.iov_len = buflen;
1335 len = recvmsg(fd, &msg, 0);
1337 log_dhcp_client(client, "could not receive message from raw "
1340 } else if ((size_t)len < sizeof(DHCPPacket))
1343 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1344 if (cmsg->cmsg_level == SOL_PACKET &&
1345 cmsg->cmsg_type == PACKET_AUXDATA &&
1346 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1347 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1349 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1354 r = dhcp_packet_verify_headers(packet, len, checksum);
1358 len -= DHCP_IP_UDP_SIZE;
1360 return client_handle_message(client, &packet->dhcp, len);
1363 int sd_dhcp_client_start(sd_dhcp_client *client) {
1366 assert_return(client, -EINVAL);
1368 r = client_initialize(client);
1372 if (client->last_addr)
1373 client->state = DHCP_STATE_INIT_REBOOT;
1375 r = client_start(client);
1377 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1379 ether_ntoa(&client->client_id.mac_addr));
1384 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1385 DHCP_CLIENT_DONT_DESTROY(client);
1387 assert_return(client, -EINVAL);
1389 client_stop(client, DHCP_EVENT_STOP);
1390 client->state = DHCP_STATE_STOPPED;
1395 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1399 assert_return(client, -EINVAL);
1400 assert_return(!client->event, -EBUSY);
1403 client->event = sd_event_ref(event);
1405 r = sd_event_default(&client->event);
1410 client->event_priority = priority;
1415 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1416 assert_return(client, -EINVAL);
1418 client->event = sd_event_unref(client->event);
1423 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1427 return client->event;
1430 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1432 assert_se(REFCNT_INC(client->n_ref) >= 2);
1437 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1438 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1439 log_dhcp_client(client, "FREE");
1441 client_initialize(client);
1443 client->receive_message =
1444 sd_event_source_unref(client->receive_message);
1446 sd_dhcp_client_detach_event(client);
1448 sd_dhcp_lease_unref(client->lease);
1450 free(client->req_opts);
1451 free(client->hostname);
1452 free(client->vendor_class_identifier);
1459 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1460 _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1462 assert_return(ret, -EINVAL);
1464 client = new0(sd_dhcp_client, 1);
1468 client->n_ref = REFCNT_INIT;
1469 client->state = DHCP_STATE_INIT;
1472 client->attempt = 1;
1474 client->req_opts_size = ELEMENTSOF(default_req_opts);
1476 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1477 if (!client->req_opts)