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_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_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,
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,
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_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_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,
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,
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,
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 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1133 log_dhcp_client(client, "not a DHCP message: ignoring");
1137 if (message->op != BOOTREPLY) {
1138 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1142 if (be32toh(message->xid) != client->xid) {
1143 log_dhcp_client(client, "received xid (%u) does not match "
1144 "expected (%u): ignoring",
1145 be32toh(message->xid), client->xid);
1149 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1150 log_dhcp_client(client, "not an ethernet packet");
1154 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1156 log_dhcp_client(client, "received chaddr does not match "
1157 "expected: ignoring");
1161 switch (client->state) {
1162 case DHCP_STATE_SELECTING:
1164 r = client_handle_offer(client, message, len);
1167 client->timeout_resend =
1168 sd_event_source_unref(client->timeout_resend);
1170 client->state = DHCP_STATE_REQUESTING;
1171 client->attempt = 1;
1173 r = sd_event_add_time(client->event,
1174 &client->timeout_resend,
1177 client_timeout_resend, client);
1181 r = sd_event_source_set_priority(client->timeout_resend,
1182 client->event_priority);
1185 } else if (r == -ENOMSG)
1186 /* invalid message, let's ignore it */
1191 case DHCP_STATE_REBOOTING:
1192 case DHCP_STATE_REQUESTING:
1193 case DHCP_STATE_RENEWING:
1194 case DHCP_STATE_REBINDING:
1196 r = client_handle_ack(client, message, len);
1197 if (r == DHCP_EVENT_NO_LEASE) {
1199 client->timeout_resend =
1200 sd_event_source_unref(client->timeout_resend);
1202 if (client->state == DHCP_STATE_REBOOTING) {
1203 r = client_initialize(client);
1207 r = client_start(client);
1211 log_dhcp_client(client, "REBOOTED");
1215 } else if (r >= 0) {
1216 client->timeout_resend =
1217 sd_event_source_unref(client->timeout_resend);
1219 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1220 DHCP_STATE_REBOOTING))
1221 notify_event = DHCP_EVENT_IP_ACQUIRE;
1222 else if (r != DHCP_EVENT_IP_ACQUIRE)
1225 client->state = DHCP_STATE_BOUND;
1226 client->attempt = 1;
1228 client->last_addr = client->lease->address;
1230 r = client_set_lease_timeouts(client);
1235 client_notify(client, notify_event);
1236 if (client->state == DHCP_STATE_STOPPED)
1240 client->receive_message =
1241 sd_event_source_unref(client->receive_message);
1242 client->fd = asynchronous_close(client->fd);
1243 } else if (r == -ENOMSG)
1244 /* invalid message, let's ignore it */
1249 case DHCP_STATE_INIT:
1250 case DHCP_STATE_INIT_REBOOT:
1251 case DHCP_STATE_BOUND:
1255 case DHCP_STATE_STOPPED:
1261 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1262 client_stop(client, r);
1267 static int client_receive_message_udp(sd_event_source *s, int fd,
1268 uint32_t revents, void *userdata) {
1269 sd_dhcp_client *client = userdata;
1270 _cleanup_free_ DHCPMessage *message = NULL;
1271 int buflen = 0, len, r;
1276 r = ioctl(fd, FIONREAD, &buflen);
1281 /* this can't be right */
1284 message = malloc0(buflen);
1288 len = read(fd, message, buflen);
1290 log_dhcp_client(client, "could not receive message from UDP "
1293 } else if ((size_t)len < sizeof(DHCPMessage))
1296 return client_handle_message(client, message, len);
1299 static int client_receive_message_raw(sd_event_source *s, int fd,
1300 uint32_t revents, void *userdata) {
1301 sd_dhcp_client *client = userdata;
1302 _cleanup_free_ DHCPPacket *packet = NULL;
1303 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1304 struct iovec iov = {};
1305 struct msghdr msg = {
1308 .msg_control = cmsgbuf,
1309 .msg_controllen = sizeof(cmsgbuf),
1311 struct cmsghdr *cmsg;
1312 bool checksum = true;
1313 int buflen = 0, len, r;
1318 r = ioctl(fd, FIONREAD, &buflen);
1323 /* this can't be right */
1326 packet = malloc0(buflen);
1330 iov.iov_base = packet;
1331 iov.iov_len = buflen;
1333 len = recvmsg(fd, &msg, 0);
1335 log_dhcp_client(client, "could not receive message from raw "
1338 } else if ((size_t)len < sizeof(DHCPPacket))
1341 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1342 if (cmsg->cmsg_level == SOL_PACKET &&
1343 cmsg->cmsg_type == PACKET_AUXDATA &&
1344 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1345 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1347 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1352 r = dhcp_packet_verify_headers(packet, len, checksum);
1356 len -= DHCP_IP_UDP_SIZE;
1358 return client_handle_message(client, &packet->dhcp, len);
1361 int sd_dhcp_client_start(sd_dhcp_client *client) {
1364 assert_return(client, -EINVAL);
1366 r = client_initialize(client);
1370 if (client->last_addr)
1371 client->state = DHCP_STATE_INIT_REBOOT;
1373 r = client_start(client);
1375 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1377 ether_ntoa(&client->client_id.mac_addr));
1382 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1383 DHCP_CLIENT_DONT_DESTROY(client);
1385 assert_return(client, -EINVAL);
1387 client_stop(client, DHCP_EVENT_STOP);
1388 client->state = DHCP_STATE_STOPPED;
1393 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1397 assert_return(client, -EINVAL);
1398 assert_return(!client->event, -EBUSY);
1401 client->event = sd_event_ref(event);
1403 r = sd_event_default(&client->event);
1408 client->event_priority = priority;
1413 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1414 assert_return(client, -EINVAL);
1416 client->event = sd_event_unref(client->event);
1421 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1425 return client->event;
1428 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1430 assert_se(REFCNT_INC(client->n_ref) >= 2);
1435 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1436 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1437 log_dhcp_client(client, "FREE");
1439 client_initialize(client);
1441 client->receive_message =
1442 sd_event_source_unref(client->receive_message);
1444 sd_dhcp_client_detach_event(client);
1446 sd_dhcp_lease_unref(client->lease);
1448 free(client->req_opts);
1449 free(client->hostname);
1450 free(client->vendor_class_identifier);
1457 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1458 _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1460 assert_return(ret, -EINVAL);
1462 client = new0(sd_dhcp_client, 1);
1466 client->n_ref = REFCNT_INIT;
1467 client->state = DHCP_STATE_INIT;
1470 client->attempt = 1;
1472 client->req_opts_size = ELEMENTSOF(default_req_opts);
1474 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1475 if (!client->req_opts)