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;
60 char *vendor_class_identifier;
66 sd_event_source *timeout_t1;
67 sd_event_source *timeout_t2;
68 sd_event_source *timeout_expire;
69 sd_dhcp_client_cb_t cb;
74 static const uint8_t default_req_opts[] = {
75 DHCP_OPTION_SUBNET_MASK,
77 DHCP_OPTION_HOST_NAME,
78 DHCP_OPTION_DOMAIN_NAME,
79 DHCP_OPTION_DOMAIN_NAME_SERVER,
80 DHCP_OPTION_NTP_SERVER,
83 static int client_receive_message_raw(sd_event_source *s, int fd,
84 uint32_t revents, void *userdata);
85 static int client_receive_message_udp(sd_event_source *s, int fd,
86 uint32_t revents, void *userdata);
87 static void client_stop(sd_dhcp_client *client, int error);
89 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
91 assert_return(client, -EINVAL);
94 client->userdata = userdata;
99 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
102 assert_return(client, -EINVAL);
103 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
104 DHCP_STATE_STOPPED), -EBUSY);
107 case DHCP_OPTION_PAD:
108 case DHCP_OPTION_OVERLOAD:
109 case DHCP_OPTION_MESSAGE_TYPE:
110 case DHCP_OPTION_PARAMETER_REQUEST_LIST:
111 case DHCP_OPTION_END:
118 for (i = 0; i < client->req_opts_size; i++)
119 if (client->req_opts[i] == option)
122 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
123 client->req_opts_size + 1))
126 client->req_opts[client->req_opts_size++] = option;
131 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
132 const struct in_addr *last_addr) {
133 assert_return(client, -EINVAL);
134 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
135 DHCP_STATE_STOPPED), -EBUSY);
138 client->last_addr = last_addr->s_addr;
140 client->last_addr = INADDR_ANY;
145 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
146 assert_return(client, -EINVAL);
147 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
148 DHCP_STATE_STOPPED), -EBUSY);
149 assert_return(interface_index > 0, -EINVAL);
151 client->index = interface_index;
156 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
157 const struct ether_addr *addr) {
158 DHCP_CLIENT_DONT_DESTROY(client);
159 bool need_restart = false;
161 assert_return(client, -EINVAL);
162 assert_return(addr, -EINVAL);
164 if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
167 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
168 log_dhcp_client(client, "Changing MAC address on running DHCP "
169 "client, restarting");
171 client_stop(client, DHCP_EVENT_STOP);
174 memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
175 client->client_id.type = 0x01;
177 if (need_restart && client->state != DHCP_STATE_STOPPED)
178 sd_dhcp_client_start(client);
183 int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
184 const char *hostname) {
185 char *new_hostname = NULL;
187 assert_return(client, -EINVAL);
189 if (streq_ptr(client->hostname, hostname))
193 new_hostname = strdup(hostname);
198 free(client->hostname);
199 client->hostname = new_hostname;
204 int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client,
206 char *new_vci = NULL;
208 assert_return(client, -EINVAL);
210 new_vci = strdup(vci);
214 free(client->vendor_class_identifier);
216 client->vendor_class_identifier = new_vci;
221 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
222 assert_return(client, -EINVAL);
223 assert_return(ret, -EINVAL);
225 if (client->state != DHCP_STATE_BOUND &&
226 client->state != DHCP_STATE_RENEWING &&
227 client->state != DHCP_STATE_REBINDING)
228 return -EADDRNOTAVAIL;
230 *ret = sd_dhcp_lease_ref(client->lease);
235 static void client_notify(sd_dhcp_client *client, int event) {
237 client->cb(client, event, client->userdata);
240 static int client_initialize(sd_dhcp_client *client) {
241 assert_return(client, -EINVAL);
243 client->receive_message =
244 sd_event_source_unref(client->receive_message);
246 client->fd = asynchronous_close(client->fd);
248 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
250 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
251 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
252 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
256 client->state = DHCP_STATE_INIT;
260 client->lease = sd_dhcp_lease_unref(client->lease);
265 static void client_stop(sd_dhcp_client *client, int error) {
269 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
272 case DHCP_EVENT_STOP:
273 log_dhcp_client(client, "STOPPED");
275 case DHCP_EVENT_NO_LEASE:
276 log_dhcp_client(client, "STOPPED: No lease");
279 log_dhcp_client(client, "STOPPED: Unknown reason");
284 client_notify(client, error);
286 client_initialize(client);
289 static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
290 uint8_t type, size_t *_optlen, size_t *_optoffset) {
291 _cleanup_free_ DHCPPacket *packet;
292 size_t optlen, optoffset, size;
297 assert(client->secs);
301 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
303 optlen = DHCP_MIN_OPTIONS_SIZE;
304 size = sizeof(DHCPPacket) + optlen;
306 packet = malloc0(size);
310 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
315 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
316 refuse to issue an DHCP lease if 'secs' is set to zero */
317 packet->dhcp.secs = htobe16(client->secs);
319 /* RFC2132 section 4.1
320 A client that cannot receive unicast IP datagrams until its protocol
321 software has been configured with an IP address SHOULD set the
322 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
323 DHCPREQUEST messages that client sends. The BROADCAST bit will
324 provide a hint to the DHCP server and BOOTP relay agent to broadcast
325 any messages to the client on the client's subnet. */
326 packet->dhcp.flags = htobe16(0x8000);
328 /* RFC2132 section 4.1.1:
329 The client MUST include its hardware address in the ’chaddr’ field, if
330 necessary for delivery of DHCP reply messages.
332 memcpy(&packet->dhcp.chaddr, &client->client_id.mac_addr, ETH_ALEN);
334 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
335 Identifier option is not set */
336 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
337 DHCP_OPTION_CLIENT_IDENTIFIER,
338 sizeof(client->client_id), &client->client_id);
343 /* RFC2131 section 3.5:
344 in its initial DHCPDISCOVER or DHCPREQUEST message, a
345 client may provide the server with a list of specific
346 parameters the client is interested in. If the client
347 includes a list of parameters in a DHCPDISCOVER message,
348 it MUST include that list in any subsequent DHCPREQUEST
351 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
352 DHCP_OPTION_PARAMETER_REQUEST_LIST,
353 client->req_opts_size, client->req_opts);
357 /* RFC2131 section 3.5:
358 The client SHOULD include the ’maximum DHCP message size’ option to
359 let the server know how large the server may make its DHCP messages.
361 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
362 than the defined default size unless the Maximum Messge Size option
365 max_size = htobe16(size);
366 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
367 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
373 *_optoffset = optoffset;
380 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
382 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
383 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
385 return dhcp_network_send_raw_socket(client->fd, &client->link,
389 static int client_send_discover(sd_dhcp_client *client) {
390 _cleanup_free_ DHCPPacket *discover = NULL;
391 size_t optoffset, optlen;
396 assert(client->state == DHCP_STATE_INIT ||
397 client->state == DHCP_STATE_SELECTING);
399 /* See RFC2131 section 4.4.1 */
401 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
404 assert(time_now >= client->start_time);
406 /* seconds between sending first and last DISCOVER
407 * must always be strictly positive to deal with broken servers */
408 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
410 r = client_message_init(client, &discover, DHCP_DISCOVER,
411 &optlen, &optoffset);
415 /* the client may suggest values for the network address
416 and lease time in the DHCPDISCOVER message. The client may include
417 the ’requested IP address’ option to suggest that a particular IP
418 address be assigned, and may include the ’IP address lease time’
419 option to suggest the lease time it would like.
421 if (client->last_addr != INADDR_ANY) {
422 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
423 DHCP_OPTION_REQUESTED_IP_ADDRESS,
424 4, &client->last_addr);
429 /* it is unclear from RFC 2131 if client should send hostname in
430 DHCPDISCOVER but dhclient does and so we do as well
432 if (client->hostname) {
433 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
434 DHCP_OPTION_HOST_NAME,
435 strlen(client->hostname), client->hostname);
440 if (client->vendor_class_identifier) {
441 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
442 DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
443 strlen(client->vendor_class_identifier),
444 client->vendor_class_identifier);
449 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
450 DHCP_OPTION_END, 0, NULL);
454 /* We currently ignore:
455 The client SHOULD wait a random time between one and ten seconds to
456 desynchronize the use of DHCP at startup.
458 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
462 log_dhcp_client(client, "DISCOVER");
467 static int client_send_request(sd_dhcp_client *client) {
468 _cleanup_free_ DHCPPacket *request = NULL;
469 size_t optoffset, optlen;
472 r = client_message_init(client, &request, DHCP_REQUEST,
473 &optlen, &optoffset);
477 switch (client->state) {
478 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
479 SELECTING should be REQUESTING)
482 case DHCP_STATE_REQUESTING:
483 /* Client inserts the address of the selected server in ’server
484 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
485 filled in with the yiaddr value from the chosen DHCPOFFER.
488 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
489 DHCP_OPTION_SERVER_IDENTIFIER,
490 4, &client->lease->server_address);
494 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
495 DHCP_OPTION_REQUESTED_IP_ADDRESS,
496 4, &client->lease->address);
502 case DHCP_STATE_INIT_REBOOT:
503 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
504 option MUST be filled in with client’s notion of its previously
505 assigned address. ’ciaddr’ MUST be zero.
507 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
508 DHCP_OPTION_REQUESTED_IP_ADDRESS,
509 4, &client->last_addr);
514 case DHCP_STATE_RENEWING:
515 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
516 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
517 client’s IP address.
521 case DHCP_STATE_REBINDING:
522 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
523 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
524 client’s IP address.
526 This message MUST be broadcast to the 0xffffffff IP broadcast address.
528 request->dhcp.ciaddr = client->lease->address;
532 case DHCP_STATE_INIT:
533 case DHCP_STATE_SELECTING:
534 case DHCP_STATE_REBOOTING:
535 case DHCP_STATE_BOUND:
536 case DHCP_STATE_STOPPED:
540 if (client->hostname) {
541 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
542 DHCP_OPTION_HOST_NAME,
543 strlen(client->hostname), client->hostname);
548 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
549 DHCP_OPTION_END, 0, NULL);
553 if (client->state == DHCP_STATE_RENEWING) {
554 r = dhcp_network_send_udp_socket(client->fd,
555 client->lease->server_address,
558 sizeof(DHCPMessage) + optoffset);
560 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
565 switch (client->state) {
566 case DHCP_STATE_REQUESTING:
567 log_dhcp_client(client, "REQUEST (requesting)");
569 case DHCP_STATE_INIT_REBOOT:
570 log_dhcp_client(client, "REQUEST (init-reboot)");
572 case DHCP_STATE_RENEWING:
573 log_dhcp_client(client, "REQUEST (renewing)");
575 case DHCP_STATE_REBINDING:
576 log_dhcp_client(client, "REQUEST (rebinding)");
579 log_dhcp_client(client, "REQUEST (invalid)");
586 static int client_start(sd_dhcp_client *client);
588 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
590 sd_dhcp_client *client = userdata;
591 DHCP_CLIENT_DONT_DESTROY(client);
592 usec_t next_timeout = 0;
599 assert(client->event);
601 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
605 switch (client->state) {
606 case DHCP_STATE_RENEWING:
608 time_left = (client->lease->t2 - client->lease->t1) / 2;
612 next_timeout = time_now + time_left * USEC_PER_SEC;
616 case DHCP_STATE_REBINDING:
618 time_left = (client->lease->lifetime - client->lease->t2) / 2;
622 next_timeout = time_now + time_left * USEC_PER_SEC;
625 case DHCP_STATE_REBOOTING:
626 /* start over as we did not receive a timely ack or nak */
627 r = client_initialize(client);
631 r = client_start(client);
635 log_dhcp_client(client, "REBOOTED");
639 case DHCP_STATE_INIT:
640 case DHCP_STATE_INIT_REBOOT:
641 case DHCP_STATE_SELECTING:
642 case DHCP_STATE_REQUESTING:
643 case DHCP_STATE_BOUND:
645 if (client->attempt < 64)
646 client->attempt *= 2;
648 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
652 case DHCP_STATE_STOPPED:
657 next_timeout += (random_u32() & 0x1fffff);
659 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
661 r = sd_event_add_time(client->event,
662 &client->timeout_resend,
664 next_timeout, 10 * USEC_PER_MSEC,
665 client_timeout_resend, client);
669 r = sd_event_source_set_priority(client->timeout_resend,
670 client->event_priority);
674 switch (client->state) {
675 case DHCP_STATE_INIT:
676 r = client_send_discover(client);
678 client->state = DHCP_STATE_SELECTING;
681 if (client->attempt >= 64)
687 case DHCP_STATE_SELECTING:
688 r = client_send_discover(client);
689 if (r < 0 && client->attempt >= 64)
694 case DHCP_STATE_INIT_REBOOT:
695 case DHCP_STATE_REQUESTING:
696 case DHCP_STATE_RENEWING:
697 case DHCP_STATE_REBINDING:
698 r = client_send_request(client);
699 if (r < 0 && client->attempt >= 64)
702 if (client->state == DHCP_STATE_INIT_REBOOT)
703 client->state = DHCP_STATE_REBOOTING;
705 client->request_sent = time_now;
709 case DHCP_STATE_REBOOTING:
710 case DHCP_STATE_BOUND:
714 case DHCP_STATE_STOPPED:
722 client_stop(client, r);
724 /* Errors were dealt with when stopping the client, don't spill
725 errors into the event loop handler */
729 static int client_initialize_events(sd_dhcp_client *client,
730 sd_event_io_handler_t io_callback) {
734 assert(client->event);
736 r = sd_event_add_io(client->event, &client->receive_message,
737 client->fd, EPOLLIN, io_callback,
742 r = sd_event_source_set_priority(client->receive_message,
743 client->event_priority);
747 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
749 r = sd_event_add_time(client->event,
750 &client->timeout_resend,
753 client_timeout_resend, client);
757 r = sd_event_source_set_priority(client->timeout_resend,
758 client->event_priority);
762 client_stop(client, r);
768 static int client_start(sd_dhcp_client *client) {
771 assert_return(client, -EINVAL);
772 assert_return(client->event, -EINVAL);
773 assert_return(client->index > 0, -EINVAL);
774 assert_return(client->fd < 0, -EBUSY);
775 assert_return(client->xid == 0, -EINVAL);
776 assert_return(client->state == DHCP_STATE_INIT ||
777 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
779 client->xid = random_u32();
781 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
783 client_stop(client, r);
788 if (client->state == DHCP_STATE_INIT) {
789 client->start_time = now(CLOCK_MONOTONIC);
793 return client_initialize_events(client, client_receive_message_raw);
796 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
798 sd_dhcp_client *client = userdata;
799 DHCP_CLIENT_DONT_DESTROY(client);
801 log_dhcp_client(client, "EXPIRED");
803 client_notify(client, DHCP_EVENT_EXPIRED);
805 /* lease was lost, start over if not freed or stopped in callback */
806 if (client->state != DHCP_STATE_STOPPED) {
807 client_initialize(client);
808 client_start(client);
814 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
815 sd_dhcp_client *client = userdata;
816 DHCP_CLIENT_DONT_DESTROY(client);
819 client->receive_message = sd_event_source_unref(client->receive_message);
820 client->fd = asynchronous_close(client->fd);
822 client->state = DHCP_STATE_REBINDING;
825 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
827 client_stop(client, r);
832 return client_initialize_events(client, client_receive_message_raw);
835 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
837 sd_dhcp_client *client = userdata;
838 DHCP_CLIENT_DONT_DESTROY(client);
841 client->state = DHCP_STATE_RENEWING;
844 r = dhcp_network_bind_udp_socket(client->lease->address,
847 log_dhcp_client(client, "could not bind UDP socket");
853 return client_initialize_events(client, client_receive_message_udp);
856 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
858 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
861 r = dhcp_lease_new(&lease);
865 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
866 if (r != DHCP_OFFER) {
867 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
871 lease->next_server = offer->siaddr;
873 lease->address = offer->yiaddr;
875 if (lease->address == INADDR_ANY ||
876 lease->server_address == INADDR_ANY ||
877 lease->lifetime == 0) {
878 log_dhcp_client(client, "receieved lease lacks address, server "
879 "address or lease lifetime, ignoring");
883 if (lease->subnet_mask == INADDR_ANY) {
884 r = dhcp_lease_set_default_subnet_mask(lease);
886 log_dhcp_client(client, "receieved lease lacks subnet "
887 "mask, and a fallback one can not be "
888 "generated, ignoring");
893 sd_dhcp_lease_unref(client->lease);
894 client->lease = lease;
897 log_dhcp_client(client, "OFFER");
902 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
904 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
907 r = dhcp_lease_new(&lease);
911 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
913 log_dhcp_client(client, "NAK");
914 return DHCP_EVENT_NO_LEASE;
918 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
922 lease->next_server = ack->siaddr;
924 lease->address = ack->yiaddr;
926 if (lease->address == INADDR_ANY ||
927 lease->server_address == INADDR_ANY ||
928 lease->lifetime == 0) {
929 log_dhcp_client(client, "receieved lease lacks address, server "
930 "address or lease lifetime, ignoring");
934 if (lease->subnet_mask == INADDR_ANY) {
935 r = dhcp_lease_set_default_subnet_mask(lease);
937 log_dhcp_client(client, "receieved lease lacks subnet "
938 "mask, and a fallback one can not be "
939 "generated, ignoring");
944 r = DHCP_EVENT_IP_ACQUIRE;
946 if (client->lease->address != lease->address ||
947 client->lease->subnet_mask != lease->subnet_mask ||
948 client->lease->router != lease->router) {
949 r = DHCP_EVENT_IP_CHANGE;
951 r = DHCP_EVENT_RENEW;
953 client->lease = sd_dhcp_lease_unref(client->lease);
956 client->lease = lease;
959 log_dhcp_client(client, "ACK");
964 static uint64_t client_compute_timeout(sd_dhcp_client *client,
965 uint32_t lifetime, double factor) {
967 assert(client->request_sent);
970 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
971 + (random_u32() & 0x1fffff);
974 static int client_set_lease_timeouts(sd_dhcp_client *client) {
976 uint64_t lifetime_timeout;
979 char time_string[FORMAT_TIMESPAN_MAX];
983 assert(client->event);
984 assert(client->lease);
985 assert(client->lease->lifetime);
987 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
988 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
989 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
991 /* don't set timers for infinite leases */
992 if (client->lease->lifetime == 0xffffffff)
995 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
998 assert(client->request_sent <= time_now);
1000 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1001 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
1002 if (client->lease->t1 && client->lease->t2) {
1003 /* both T1 and T2 are given */
1004 if (client->lease->t1 < client->lease->t2 &&
1005 client->lease->t2 < client->lease->lifetime) {
1006 /* they are both valid */
1007 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1008 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1011 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1012 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1013 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1014 client->lease->t1 = client->lease->lifetime / 2;
1016 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
1017 /* only T2 is given, and it is valid */
1018 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1019 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1020 client->lease->t1 = client->lease->lifetime / 2;
1021 if (t2_timeout <= t1_timeout) {
1022 /* the computed T1 would be invalid, so discard T2 */
1023 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1024 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1026 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
1027 /* only T1 is given, and it is valid */
1028 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1029 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1030 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1031 if (t2_timeout <= t1_timeout) {
1032 /* the computed T2 would be invalid, so discard T1 */
1033 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1034 client->lease->t2 = client->lease->lifetime / 2;
1037 /* fall back to the default timeouts */
1038 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1039 client->lease->t1 = client->lease->lifetime / 2;
1040 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1041 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1044 /* arm lifetime timeout */
1045 r = sd_event_add_time(client->event, &client->timeout_expire,
1047 lifetime_timeout, 10 * USEC_PER_MSEC,
1048 client_timeout_expire, client);
1052 r = sd_event_source_set_priority(client->timeout_expire,
1053 client->event_priority);
1057 log_dhcp_client(client, "lease expires in %s",
1058 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1059 lifetime_timeout - time_now, 0));
1061 /* don't arm earlier timeouts if this has already expired */
1062 if (lifetime_timeout <= time_now)
1065 /* arm T2 timeout */
1066 r = sd_event_add_time(client->event,
1067 &client->timeout_t2,
1071 client_timeout_t2, client);
1075 r = sd_event_source_set_priority(client->timeout_t2,
1076 client->event_priority);
1080 log_dhcp_client(client, "T2 expires in %s",
1081 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1082 t2_timeout - time_now, 0));
1084 /* don't arm earlier timeout if this has already expired */
1085 if (t2_timeout <= time_now)
1088 /* arm T1 timeout */
1089 r = sd_event_add_time(client->event,
1090 &client->timeout_t1,
1092 t1_timeout, 10 * USEC_PER_MSEC,
1093 client_timeout_t1, client);
1097 r = sd_event_source_set_priority(client->timeout_t1,
1098 client->event_priority);
1102 log_dhcp_client(client, "T1 expires in %s",
1103 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1104 t1_timeout - time_now, 0));
1109 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1111 DHCP_CLIENT_DONT_DESTROY(client);
1112 int r = 0, notify_event = 0;
1115 assert(client->event);
1118 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1119 log_dhcp_client(client, "not a DHCP message: ignoring");
1123 if (message->op != BOOTREPLY) {
1124 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1128 if (be32toh(message->xid) != client->xid) {
1129 log_dhcp_client(client, "received xid (%u) does not match "
1130 "expected (%u): ignoring",
1131 be32toh(message->xid), client->xid);
1135 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1136 log_dhcp_client(client, "not an ethernet packet");
1140 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1142 log_dhcp_client(client, "received chaddr does not match "
1143 "expected: ignoring");
1147 switch (client->state) {
1148 case DHCP_STATE_SELECTING:
1150 r = client_handle_offer(client, message, len);
1153 client->timeout_resend =
1154 sd_event_source_unref(client->timeout_resend);
1156 client->state = DHCP_STATE_REQUESTING;
1157 client->attempt = 1;
1159 r = sd_event_add_time(client->event,
1160 &client->timeout_resend,
1163 client_timeout_resend, client);
1167 r = sd_event_source_set_priority(client->timeout_resend,
1168 client->event_priority);
1171 } else if (r == -ENOMSG)
1172 /* invalid message, let's ignore it */
1177 case DHCP_STATE_REBOOTING:
1178 case DHCP_STATE_REQUESTING:
1179 case DHCP_STATE_RENEWING:
1180 case DHCP_STATE_REBINDING:
1182 r = client_handle_ack(client, message, len);
1183 if (r == DHCP_EVENT_NO_LEASE) {
1185 client->timeout_resend =
1186 sd_event_source_unref(client->timeout_resend);
1188 if (client->state == DHCP_STATE_REBOOTING) {
1189 r = client_initialize(client);
1193 r = client_start(client);
1197 log_dhcp_client(client, "REBOOTED");
1201 } else if (r >= 0) {
1202 client->timeout_resend =
1203 sd_event_source_unref(client->timeout_resend);
1205 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1206 DHCP_STATE_REBOOTING))
1207 notify_event = DHCP_EVENT_IP_ACQUIRE;
1208 else if (r != DHCP_EVENT_IP_ACQUIRE)
1211 client->state = DHCP_STATE_BOUND;
1212 client->attempt = 1;
1214 client->last_addr = client->lease->address;
1216 r = client_set_lease_timeouts(client);
1221 client_notify(client, notify_event);
1222 if (client->state == DHCP_STATE_STOPPED)
1226 client->receive_message =
1227 sd_event_source_unref(client->receive_message);
1228 client->fd = asynchronous_close(client->fd);
1229 } else if (r == -ENOMSG)
1230 /* invalid message, let's ignore it */
1235 case DHCP_STATE_INIT:
1236 case DHCP_STATE_INIT_REBOOT:
1237 case DHCP_STATE_BOUND:
1241 case DHCP_STATE_STOPPED:
1247 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1248 client_stop(client, r);
1253 static int client_receive_message_udp(sd_event_source *s, int fd,
1254 uint32_t revents, void *userdata) {
1255 sd_dhcp_client *client = userdata;
1256 _cleanup_free_ DHCPMessage *message = NULL;
1257 int buflen = 0, len, r;
1262 r = ioctl(fd, FIONREAD, &buflen);
1267 /* this can't be right */
1270 message = malloc0(buflen);
1274 len = read(fd, message, buflen);
1276 log_dhcp_client(client, "could not receive message from UDP "
1279 } else if ((size_t)len < sizeof(DHCPMessage))
1282 return client_handle_message(client, message, len);
1285 static int client_receive_message_raw(sd_event_source *s, int fd,
1286 uint32_t revents, void *userdata) {
1287 sd_dhcp_client *client = userdata;
1288 _cleanup_free_ DHCPPacket *packet = NULL;
1289 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1290 struct iovec iov = {};
1291 struct msghdr msg = {
1294 .msg_control = cmsgbuf,
1295 .msg_controllen = sizeof(cmsgbuf),
1297 struct cmsghdr *cmsg;
1298 bool checksum = true;
1299 int buflen = 0, len, r;
1304 r = ioctl(fd, FIONREAD, &buflen);
1309 /* this can't be right */
1312 packet = malloc0(buflen);
1316 iov.iov_base = packet;
1317 iov.iov_len = buflen;
1319 len = recvmsg(fd, &msg, 0);
1321 log_dhcp_client(client, "could not receive message from raw "
1324 } else if ((size_t)len < sizeof(DHCPPacket))
1327 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1328 if (cmsg->cmsg_level == SOL_PACKET &&
1329 cmsg->cmsg_type == PACKET_AUXDATA &&
1330 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1331 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1333 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1338 r = dhcp_packet_verify_headers(packet, len, checksum);
1342 len -= DHCP_IP_UDP_SIZE;
1344 return client_handle_message(client, &packet->dhcp, len);
1347 int sd_dhcp_client_start(sd_dhcp_client *client) {
1350 assert_return(client, -EINVAL);
1352 r = client_initialize(client);
1356 if (client->last_addr)
1357 client->state = DHCP_STATE_INIT_REBOOT;
1359 r = client_start(client);
1361 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1363 ether_ntoa(&client->client_id.mac_addr));
1368 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1369 DHCP_CLIENT_DONT_DESTROY(client);
1371 assert_return(client, -EINVAL);
1373 client_stop(client, DHCP_EVENT_STOP);
1374 client->state = DHCP_STATE_STOPPED;
1379 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1383 assert_return(client, -EINVAL);
1384 assert_return(!client->event, -EBUSY);
1387 client->event = sd_event_ref(event);
1389 r = sd_event_default(&client->event);
1394 client->event_priority = priority;
1399 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1400 assert_return(client, -EINVAL);
1402 client->event = sd_event_unref(client->event);
1407 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1411 return client->event;
1414 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1416 assert_se(REFCNT_INC(client->n_ref) >= 2);
1421 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1422 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1423 log_dhcp_client(client, "FREE");
1425 client_initialize(client);
1427 client->receive_message =
1428 sd_event_source_unref(client->receive_message);
1430 sd_dhcp_client_detach_event(client);
1432 sd_dhcp_lease_unref(client->lease);
1434 free(client->req_opts);
1435 free(client->hostname);
1436 free(client->vendor_class_identifier);
1443 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1444 _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1446 assert_return(ret, -EINVAL);
1448 client = new0(sd_dhcp_client, 1);
1452 client->n_ref = REFCNT_INIT;
1453 client->state = DHCP_STATE_INIT;
1456 client->attempt = 1;
1458 client->req_opts_size = ELEMENTSOF(default_req_opts);
1460 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1461 if (!client->req_opts)