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));
279 else if (error == DHCP_EVENT_STOP)
280 log_dhcp_client(client, "STOPPED");
282 log_dhcp_client(client, "STOPPED: Unknown event");
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.
327 Note: some interfaces needs this to be enabled, but some networks
328 needs this to be disabled as broadcasts are filteretd, so this
329 needs to be configurable */
330 if (client->request_broadcast)
331 packet->dhcp.flags = htobe16(0x8000);
333 /* RFC2132 section 4.1.1:
334 The client MUST include its hardware address in the ’chaddr’ field, if
335 necessary for delivery of DHCP reply messages.
337 memcpy(&packet->dhcp.chaddr, &client->client_id.mac_addr, ETH_ALEN);
339 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
340 Identifier option is not set */
341 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
342 DHCP_OPTION_CLIENT_IDENTIFIER,
343 sizeof(client->client_id), &client->client_id);
348 /* RFC2131 section 3.5:
349 in its initial DHCPDISCOVER or DHCPREQUEST message, a
350 client may provide the server with a list of specific
351 parameters the client is interested in. If the client
352 includes a list of parameters in a DHCPDISCOVER message,
353 it MUST include that list in any subsequent DHCPREQUEST
356 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
357 DHCP_OPTION_PARAMETER_REQUEST_LIST,
358 client->req_opts_size, client->req_opts);
362 /* RFC2131 section 3.5:
363 The client SHOULD include the ’maximum DHCP message size’ option to
364 let the server know how large the server may make its DHCP messages.
366 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
367 than the defined default size unless the Maximum Messge Size option
370 max_size = htobe16(size);
371 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
372 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
378 *_optoffset = optoffset;
385 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
387 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
388 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
390 return dhcp_network_send_raw_socket(client->fd, &client->link,
394 static int client_send_discover(sd_dhcp_client *client) {
395 _cleanup_free_ DHCPPacket *discover = NULL;
396 size_t optoffset, optlen;
401 assert(client->state == DHCP_STATE_INIT ||
402 client->state == DHCP_STATE_SELECTING);
404 /* See RFC2131 section 4.4.1 */
406 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
409 assert(time_now >= client->start_time);
411 /* seconds between sending first and last DISCOVER
412 * must always be strictly positive to deal with broken servers */
413 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
415 r = client_message_init(client, &discover, DHCP_DISCOVER,
416 &optlen, &optoffset);
420 /* the client may suggest values for the network address
421 and lease time in the DHCPDISCOVER message. The client may include
422 the ’requested IP address’ option to suggest that a particular IP
423 address be assigned, and may include the ’IP address lease time’
424 option to suggest the lease time it would like.
426 if (client->last_addr != INADDR_ANY) {
427 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
428 DHCP_OPTION_REQUESTED_IP_ADDRESS,
429 4, &client->last_addr);
434 /* it is unclear from RFC 2131 if client should send hostname in
435 DHCPDISCOVER but dhclient does and so we do as well
437 if (client->hostname) {
438 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
439 DHCP_OPTION_HOST_NAME,
440 strlen(client->hostname), client->hostname);
445 if (client->vendor_class_identifier) {
446 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
447 DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
448 strlen(client->vendor_class_identifier),
449 client->vendor_class_identifier);
454 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
455 DHCP_OPTION_END, 0, NULL);
459 /* We currently ignore:
460 The client SHOULD wait a random time between one and ten seconds to
461 desynchronize the use of DHCP at startup.
463 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
467 log_dhcp_client(client, "DISCOVER");
472 static int client_send_request(sd_dhcp_client *client) {
473 _cleanup_free_ DHCPPacket *request = NULL;
474 size_t optoffset, optlen;
477 r = client_message_init(client, &request, DHCP_REQUEST,
478 &optlen, &optoffset);
482 switch (client->state) {
483 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
484 SELECTING should be REQUESTING)
487 case DHCP_STATE_REQUESTING:
488 /* Client inserts the address of the selected server in ’server
489 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
490 filled in with the yiaddr value from the chosen DHCPOFFER.
493 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
494 DHCP_OPTION_SERVER_IDENTIFIER,
495 4, &client->lease->server_address);
499 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
500 DHCP_OPTION_REQUESTED_IP_ADDRESS,
501 4, &client->lease->address);
507 case DHCP_STATE_INIT_REBOOT:
508 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
509 option MUST be filled in with client’s notion of its previously
510 assigned address. ’ciaddr’ MUST be zero.
512 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
513 DHCP_OPTION_REQUESTED_IP_ADDRESS,
514 4, &client->last_addr);
519 case DHCP_STATE_RENEWING:
520 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
521 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
522 client’s IP address.
526 case DHCP_STATE_REBINDING:
527 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
528 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
529 client’s IP address.
531 This message MUST be broadcast to the 0xffffffff IP broadcast address.
533 request->dhcp.ciaddr = client->lease->address;
537 case DHCP_STATE_INIT:
538 case DHCP_STATE_SELECTING:
539 case DHCP_STATE_REBOOTING:
540 case DHCP_STATE_BOUND:
541 case DHCP_STATE_STOPPED:
545 if (client->hostname) {
546 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
547 DHCP_OPTION_HOST_NAME,
548 strlen(client->hostname), client->hostname);
553 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
554 DHCP_OPTION_END, 0, NULL);
558 if (client->state == DHCP_STATE_RENEWING) {
559 r = dhcp_network_send_udp_socket(client->fd,
560 client->lease->server_address,
563 sizeof(DHCPMessage) + optoffset);
565 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
570 switch (client->state) {
571 case DHCP_STATE_REQUESTING:
572 log_dhcp_client(client, "REQUEST (requesting)");
574 case DHCP_STATE_INIT_REBOOT:
575 log_dhcp_client(client, "REQUEST (init-reboot)");
577 case DHCP_STATE_RENEWING:
578 log_dhcp_client(client, "REQUEST (renewing)");
580 case DHCP_STATE_REBINDING:
581 log_dhcp_client(client, "REQUEST (rebinding)");
584 log_dhcp_client(client, "REQUEST (invalid)");
591 static int client_start(sd_dhcp_client *client);
593 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
595 sd_dhcp_client *client = userdata;
596 DHCP_CLIENT_DONT_DESTROY(client);
597 usec_t next_timeout = 0;
604 assert(client->event);
606 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
610 switch (client->state) {
611 case DHCP_STATE_RENEWING:
613 time_left = (client->lease->t2 - client->lease->t1) / 2;
617 next_timeout = time_now + time_left * USEC_PER_SEC;
621 case DHCP_STATE_REBINDING:
623 time_left = (client->lease->lifetime - client->lease->t2) / 2;
627 next_timeout = time_now + time_left * USEC_PER_SEC;
630 case DHCP_STATE_REBOOTING:
631 /* start over as we did not receive a timely ack or nak */
632 r = client_initialize(client);
636 r = client_start(client);
640 log_dhcp_client(client, "REBOOTED");
644 case DHCP_STATE_INIT:
645 case DHCP_STATE_INIT_REBOOT:
646 case DHCP_STATE_SELECTING:
647 case DHCP_STATE_REQUESTING:
648 case DHCP_STATE_BOUND:
650 if (client->attempt < 64)
651 client->attempt *= 2;
653 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
657 case DHCP_STATE_STOPPED:
662 next_timeout += (random_u32() & 0x1fffff);
664 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
666 r = sd_event_add_time(client->event,
667 &client->timeout_resend,
668 clock_boottime_or_monotonic(),
669 next_timeout, 10 * USEC_PER_MSEC,
670 client_timeout_resend, client);
674 r = sd_event_source_set_priority(client->timeout_resend,
675 client->event_priority);
679 switch (client->state) {
680 case DHCP_STATE_INIT:
681 r = client_send_discover(client);
683 client->state = DHCP_STATE_SELECTING;
686 if (client->attempt >= 64)
692 case DHCP_STATE_SELECTING:
693 r = client_send_discover(client);
694 if (r < 0 && client->attempt >= 64)
699 case DHCP_STATE_INIT_REBOOT:
700 case DHCP_STATE_REQUESTING:
701 case DHCP_STATE_RENEWING:
702 case DHCP_STATE_REBINDING:
703 r = client_send_request(client);
704 if (r < 0 && client->attempt >= 64)
707 if (client->state == DHCP_STATE_INIT_REBOOT)
708 client->state = DHCP_STATE_REBOOTING;
710 client->request_sent = time_now;
714 case DHCP_STATE_REBOOTING:
715 case DHCP_STATE_BOUND:
719 case DHCP_STATE_STOPPED:
727 client_stop(client, r);
729 /* Errors were dealt with when stopping the client, don't spill
730 errors into the event loop handler */
734 static int client_initialize_io_events(sd_dhcp_client *client,
735 sd_event_io_handler_t io_callback) {
739 assert(client->event);
741 r = sd_event_add_io(client->event, &client->receive_message,
742 client->fd, EPOLLIN, io_callback,
747 r = sd_event_source_set_priority(client->receive_message,
748 client->event_priority);
754 client_stop(client, r);
759 static int client_initialize_time_events(sd_dhcp_client *client) {
763 assert(client->event);
765 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
767 r = sd_event_add_time(client->event,
768 &client->timeout_resend,
769 clock_boottime_or_monotonic(),
771 client_timeout_resend, client);
775 r = sd_event_source_set_priority(client->timeout_resend,
776 client->event_priority);
780 client_stop(client, r);
786 static int client_initialize_events(sd_dhcp_client *client,
787 sd_event_io_handler_t io_callback) {
788 client_initialize_io_events(client, io_callback);
789 client_initialize_time_events(client);
794 static int client_start(sd_dhcp_client *client) {
797 assert_return(client, -EINVAL);
798 assert_return(client->event, -EINVAL);
799 assert_return(client->index > 0, -EINVAL);
800 assert_return(client->fd < 0, -EBUSY);
801 assert_return(client->xid == 0, -EINVAL);
802 assert_return(client->state == DHCP_STATE_INIT ||
803 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
805 client->xid = random_u32();
807 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
809 client_stop(client, r);
814 if (client->state == DHCP_STATE_INIT) {
815 client->start_time = now(clock_boottime_or_monotonic());
819 return client_initialize_events(client, client_receive_message_raw);
822 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
824 sd_dhcp_client *client = userdata;
825 DHCP_CLIENT_DONT_DESTROY(client);
827 log_dhcp_client(client, "EXPIRED");
829 client_notify(client, DHCP_EVENT_EXPIRED);
831 /* lease was lost, start over if not freed or stopped in callback */
832 if (client->state != DHCP_STATE_STOPPED) {
833 client_initialize(client);
834 client_start(client);
840 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
841 sd_dhcp_client *client = userdata;
842 DHCP_CLIENT_DONT_DESTROY(client);
845 client->receive_message = sd_event_source_unref(client->receive_message);
846 client->fd = asynchronous_close(client->fd);
848 client->state = DHCP_STATE_REBINDING;
851 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
853 client_stop(client, r);
858 return client_initialize_events(client, client_receive_message_raw);
861 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
863 sd_dhcp_client *client = userdata;
864 DHCP_CLIENT_DONT_DESTROY(client);
867 client->state = DHCP_STATE_RENEWING;
870 return client_initialize_time_events(client);
873 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
875 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
878 r = dhcp_lease_new(&lease);
882 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
883 if (r != DHCP_OFFER) {
884 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
888 lease->next_server = offer->siaddr;
890 lease->address = offer->yiaddr;
892 if (lease->address == INADDR_ANY ||
893 lease->server_address == INADDR_ANY ||
894 lease->lifetime == 0) {
895 log_dhcp_client(client, "receieved lease lacks address, server "
896 "address or lease lifetime, ignoring");
900 if (lease->subnet_mask == INADDR_ANY) {
901 r = dhcp_lease_set_default_subnet_mask(lease);
903 log_dhcp_client(client, "receieved lease lacks subnet "
904 "mask, and a fallback one can not be "
905 "generated, ignoring");
910 sd_dhcp_lease_unref(client->lease);
911 client->lease = lease;
914 log_dhcp_client(client, "OFFER");
919 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
921 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
924 r = dhcp_lease_new(&lease);
928 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
930 log_dhcp_client(client, "NAK");
931 return -EADDRNOTAVAIL;
935 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
939 lease->next_server = ack->siaddr;
941 lease->address = ack->yiaddr;
943 if (lease->address == INADDR_ANY ||
944 lease->server_address == INADDR_ANY ||
945 lease->lifetime == 0) {
946 log_dhcp_client(client, "receieved lease lacks address, server "
947 "address or lease lifetime, ignoring");
951 if (lease->subnet_mask == INADDR_ANY) {
952 r = dhcp_lease_set_default_subnet_mask(lease);
954 log_dhcp_client(client, "receieved lease lacks subnet "
955 "mask, and a fallback one can not be "
956 "generated, ignoring");
961 r = DHCP_EVENT_IP_ACQUIRE;
963 if (client->lease->address != lease->address ||
964 client->lease->subnet_mask != lease->subnet_mask ||
965 client->lease->router != lease->router) {
966 r = DHCP_EVENT_IP_CHANGE;
968 r = DHCP_EVENT_RENEW;
970 client->lease = sd_dhcp_lease_unref(client->lease);
973 client->lease = lease;
976 log_dhcp_client(client, "ACK");
981 static uint64_t client_compute_timeout(sd_dhcp_client *client,
982 uint32_t lifetime, double factor) {
984 assert(client->request_sent);
987 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
988 + (random_u32() & 0x1fffff);
991 static int client_set_lease_timeouts(sd_dhcp_client *client) {
993 uint64_t lifetime_timeout;
996 char time_string[FORMAT_TIMESPAN_MAX];
1000 assert(client->event);
1001 assert(client->lease);
1002 assert(client->lease->lifetime);
1004 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1005 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1006 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
1008 /* don't set timers for infinite leases */
1009 if (client->lease->lifetime == 0xffffffff)
1012 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1015 assert(client->request_sent <= time_now);
1017 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1018 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
1019 if (client->lease->t1 && client->lease->t2) {
1020 /* both T1 and T2 are given */
1021 if (client->lease->t1 < client->lease->t2 &&
1022 client->lease->t2 < client->lease->lifetime) {
1023 /* they are both valid */
1024 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1025 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1028 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1029 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1030 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1031 client->lease->t1 = client->lease->lifetime / 2;
1033 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
1034 /* only T2 is given, and it is valid */
1035 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1036 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1037 client->lease->t1 = client->lease->lifetime / 2;
1038 if (t2_timeout <= t1_timeout) {
1039 /* the computed T1 would be invalid, so discard T2 */
1040 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1041 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1043 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
1044 /* only T1 is given, and it is valid */
1045 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1046 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1047 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1048 if (t2_timeout <= t1_timeout) {
1049 /* the computed T2 would be invalid, so discard T1 */
1050 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1051 client->lease->t2 = client->lease->lifetime / 2;
1054 /* fall back to the default timeouts */
1055 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1056 client->lease->t1 = client->lease->lifetime / 2;
1057 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1058 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1061 /* arm lifetime timeout */
1062 r = sd_event_add_time(client->event, &client->timeout_expire,
1063 clock_boottime_or_monotonic(),
1064 lifetime_timeout, 10 * USEC_PER_MSEC,
1065 client_timeout_expire, client);
1069 r = sd_event_source_set_priority(client->timeout_expire,
1070 client->event_priority);
1074 log_dhcp_client(client, "lease expires in %s",
1075 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1076 lifetime_timeout - time_now, 0));
1078 /* don't arm earlier timeouts if this has already expired */
1079 if (lifetime_timeout <= time_now)
1082 /* arm T2 timeout */
1083 r = sd_event_add_time(client->event,
1084 &client->timeout_t2,
1085 clock_boottime_or_monotonic(),
1088 client_timeout_t2, client);
1092 r = sd_event_source_set_priority(client->timeout_t2,
1093 client->event_priority);
1097 log_dhcp_client(client, "T2 expires in %s",
1098 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1099 t2_timeout - time_now, 0));
1101 /* don't arm earlier timeout if this has already expired */
1102 if (t2_timeout <= time_now)
1105 /* arm T1 timeout */
1106 r = sd_event_add_time(client->event,
1107 &client->timeout_t1,
1108 clock_boottime_or_monotonic(),
1109 t1_timeout, 10 * USEC_PER_MSEC,
1110 client_timeout_t1, client);
1114 r = sd_event_source_set_priority(client->timeout_t1,
1115 client->event_priority);
1119 log_dhcp_client(client, "T1 expires in %s",
1120 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1121 t1_timeout - time_now, 0));
1126 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1128 DHCP_CLIENT_DONT_DESTROY(client);
1129 int r = 0, notify_event = 0;
1132 assert(client->event);
1135 switch (client->state) {
1136 case DHCP_STATE_SELECTING:
1138 r = client_handle_offer(client, message, len);
1141 client->timeout_resend =
1142 sd_event_source_unref(client->timeout_resend);
1144 client->state = DHCP_STATE_REQUESTING;
1145 client->attempt = 1;
1147 r = sd_event_add_time(client->event,
1148 &client->timeout_resend,
1149 clock_boottime_or_monotonic(),
1151 client_timeout_resend, client);
1155 r = sd_event_source_set_priority(client->timeout_resend,
1156 client->event_priority);
1159 } else if (r == -ENOMSG)
1160 /* invalid message, let's ignore it */
1165 case DHCP_STATE_REBOOTING:
1166 case DHCP_STATE_REQUESTING:
1167 case DHCP_STATE_RENEWING:
1168 case DHCP_STATE_REBINDING:
1170 r = client_handle_ack(client, message, len);
1172 client->timeout_resend =
1173 sd_event_source_unref(client->timeout_resend);
1175 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1176 DHCP_STATE_REBOOTING))
1177 notify_event = DHCP_EVENT_IP_ACQUIRE;
1178 else if (r != DHCP_EVENT_IP_ACQUIRE)
1181 client->state = DHCP_STATE_BOUND;
1182 client->attempt = 1;
1184 client->last_addr = client->lease->address;
1186 r = client_set_lease_timeouts(client);
1190 r = dhcp_network_bind_udp_socket(client->lease->address,
1193 log_dhcp_client(client, "could not bind UDP socket");
1199 client_initialize_io_events(client, client_receive_message_udp);
1202 client_notify(client, notify_event);
1203 if (client->state == DHCP_STATE_STOPPED)
1207 } else if (r == -EADDRNOTAVAIL) {
1208 /* got a NAK, let's restart the client */
1209 client->timeout_resend =
1210 sd_event_source_unref(client->timeout_resend);
1212 r = client_initialize(client);
1216 r = client_start(client);
1220 log_dhcp_client(client, "REBOOTED");
1223 } else if (r == -ENOMSG)
1224 /* invalid message, let's ignore it */
1229 case DHCP_STATE_INIT:
1230 case DHCP_STATE_INIT_REBOOT:
1231 case DHCP_STATE_BOUND:
1235 case DHCP_STATE_STOPPED:
1242 client_stop(client, r);
1247 static int client_receive_message_udp(sd_event_source *s, int fd,
1248 uint32_t revents, void *userdata) {
1249 sd_dhcp_client *client = userdata;
1250 _cleanup_free_ DHCPMessage *message = NULL;
1251 int buflen = 0, len, r;
1256 r = ioctl(fd, FIONREAD, &buflen);
1261 /* this can't be right */
1264 message = malloc0(buflen);
1268 len = read(fd, message, buflen);
1270 log_dhcp_client(client, "could not receive message from UDP "
1273 } else if ((size_t)len < sizeof(DHCPMessage)) {
1274 log_dhcp_client(client, "too small to be a DHCP message: ignoring");
1278 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1279 log_dhcp_client(client, "not a DHCP message: ignoring");
1283 if (message->op != BOOTREPLY) {
1284 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1288 if (be32toh(message->xid) != client->xid) {
1289 log_dhcp_client(client, "received xid (%u) does not match "
1290 "expected (%u): ignoring",
1291 be32toh(message->xid), client->xid);
1295 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1296 log_dhcp_client(client, "not an ethernet packet");
1300 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1302 log_dhcp_client(client, "received chaddr does not match "
1303 "expected: ignoring");
1307 return client_handle_message(client, message, len);
1310 static int client_receive_message_raw(sd_event_source *s, int fd,
1311 uint32_t revents, void *userdata) {
1312 sd_dhcp_client *client = userdata;
1313 _cleanup_free_ DHCPPacket *packet = NULL;
1314 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1315 struct iovec iov = {};
1316 struct msghdr msg = {
1319 .msg_control = cmsgbuf,
1320 .msg_controllen = sizeof(cmsgbuf),
1322 struct cmsghdr *cmsg;
1323 bool checksum = true;
1324 int buflen = 0, len, r;
1329 r = ioctl(fd, FIONREAD, &buflen);
1334 /* this can't be right */
1337 packet = malloc0(buflen);
1341 iov.iov_base = packet;
1342 iov.iov_len = buflen;
1344 len = recvmsg(fd, &msg, 0);
1346 log_dhcp_client(client, "could not receive message from raw "
1349 } else if ((size_t)len < sizeof(DHCPPacket))
1352 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1353 if (cmsg->cmsg_level == SOL_PACKET &&
1354 cmsg->cmsg_type == PACKET_AUXDATA &&
1355 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1356 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1358 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1363 r = dhcp_packet_verify_headers(packet, len, checksum);
1367 len -= DHCP_IP_UDP_SIZE;
1369 return client_handle_message(client, &packet->dhcp, len);
1372 int sd_dhcp_client_start(sd_dhcp_client *client) {
1375 assert_return(client, -EINVAL);
1377 r = client_initialize(client);
1381 if (client->last_addr)
1382 client->state = DHCP_STATE_INIT_REBOOT;
1384 r = client_start(client);
1386 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1388 ether_ntoa(&client->client_id.mac_addr));
1393 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1394 DHCP_CLIENT_DONT_DESTROY(client);
1396 assert_return(client, -EINVAL);
1398 client_stop(client, DHCP_EVENT_STOP);
1399 client->state = DHCP_STATE_STOPPED;
1404 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1408 assert_return(client, -EINVAL);
1409 assert_return(!client->event, -EBUSY);
1412 client->event = sd_event_ref(event);
1414 r = sd_event_default(&client->event);
1419 client->event_priority = priority;
1424 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1425 assert_return(client, -EINVAL);
1427 client->event = sd_event_unref(client->event);
1432 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1436 return client->event;
1439 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1441 assert_se(REFCNT_INC(client->n_ref) >= 2);
1446 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1447 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1448 log_dhcp_client(client, "FREE");
1450 client_initialize(client);
1452 client->receive_message =
1453 sd_event_source_unref(client->receive_message);
1455 sd_dhcp_client_detach_event(client);
1457 sd_dhcp_lease_unref(client->lease);
1459 free(client->req_opts);
1460 free(client->hostname);
1461 free(client->vendor_class_identifier);
1468 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1469 _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1471 assert_return(ret, -EINVAL);
1473 client = new0(sd_dhcp_client, 1);
1477 client->n_ref = REFCNT_INIT;
1478 client->state = DHCP_STATE_INIT;
1481 client->attempt = 1;
1483 client->req_opts_size = ELEMENTSOF(default_req_opts);
1485 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1486 if (!client->req_opts)