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);
866 client->state = DHCP_STATE_RENEWING;
869 return client_initialize_time_events(client);
872 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
874 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
877 r = dhcp_lease_new(&lease);
881 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
882 if (r != DHCP_OFFER) {
883 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
887 lease->next_server = offer->siaddr;
889 lease->address = offer->yiaddr;
891 if (lease->address == INADDR_ANY ||
892 lease->server_address == INADDR_ANY ||
893 lease->lifetime == 0) {
894 log_dhcp_client(client, "receieved lease lacks address, server "
895 "address or lease lifetime, ignoring");
899 if (lease->subnet_mask == INADDR_ANY) {
900 r = dhcp_lease_set_default_subnet_mask(lease);
902 log_dhcp_client(client, "receieved lease lacks subnet "
903 "mask, and a fallback one can not be "
904 "generated, ignoring");
909 sd_dhcp_lease_unref(client->lease);
910 client->lease = lease;
913 log_dhcp_client(client, "OFFER");
918 static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
922 r = dhcp_option_parse(force, len, NULL, NULL);
923 if (r != DHCP_FORCERENEW)
926 log_dhcp_client(client, "FORCERENEW");
931 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
933 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
936 r = dhcp_lease_new(&lease);
940 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
942 log_dhcp_client(client, "NAK");
943 return -EADDRNOTAVAIL;
947 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
951 lease->next_server = ack->siaddr;
953 lease->address = ack->yiaddr;
955 if (lease->address == INADDR_ANY ||
956 lease->server_address == INADDR_ANY ||
957 lease->lifetime == 0) {
958 log_dhcp_client(client, "receieved lease lacks address, server "
959 "address or lease lifetime, ignoring");
963 if (lease->subnet_mask == INADDR_ANY) {
964 r = dhcp_lease_set_default_subnet_mask(lease);
966 log_dhcp_client(client, "receieved lease lacks subnet "
967 "mask, and a fallback one can not be "
968 "generated, ignoring");
973 r = DHCP_EVENT_IP_ACQUIRE;
975 if (client->lease->address != lease->address ||
976 client->lease->subnet_mask != lease->subnet_mask ||
977 client->lease->router != lease->router) {
978 r = DHCP_EVENT_IP_CHANGE;
980 r = DHCP_EVENT_RENEW;
982 client->lease = sd_dhcp_lease_unref(client->lease);
985 client->lease = lease;
988 log_dhcp_client(client, "ACK");
993 static uint64_t client_compute_timeout(sd_dhcp_client *client,
994 uint32_t lifetime, double factor) {
996 assert(client->request_sent);
999 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
1000 + (random_u32() & 0x1fffff);
1003 static int client_set_lease_timeouts(sd_dhcp_client *client) {
1005 uint64_t lifetime_timeout;
1006 uint64_t t2_timeout;
1007 uint64_t t1_timeout;
1008 char time_string[FORMAT_TIMESPAN_MAX];
1012 assert(client->event);
1013 assert(client->lease);
1014 assert(client->lease->lifetime);
1016 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1017 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1018 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
1020 /* don't set timers for infinite leases */
1021 if (client->lease->lifetime == 0xffffffff)
1024 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1027 assert(client->request_sent <= time_now);
1029 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1030 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
1031 if (client->lease->t1 && client->lease->t2) {
1032 /* both T1 and T2 are given */
1033 if (client->lease->t1 < client->lease->t2 &&
1034 client->lease->t2 < client->lease->lifetime) {
1035 /* they are both valid */
1036 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1037 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1040 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1041 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1042 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1043 client->lease->t1 = client->lease->lifetime / 2;
1045 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
1046 /* only T2 is given, and it is valid */
1047 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1048 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1049 client->lease->t1 = client->lease->lifetime / 2;
1050 if (t2_timeout <= t1_timeout) {
1051 /* the computed T1 would be invalid, so discard T2 */
1052 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1053 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1055 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
1056 /* only T1 is given, and it is valid */
1057 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1058 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1059 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1060 if (t2_timeout <= t1_timeout) {
1061 /* the computed T2 would be invalid, so discard T1 */
1062 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1063 client->lease->t2 = client->lease->lifetime / 2;
1066 /* fall back to the default timeouts */
1067 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1068 client->lease->t1 = client->lease->lifetime / 2;
1069 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1070 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1073 /* arm lifetime timeout */
1074 r = sd_event_add_time(client->event, &client->timeout_expire,
1075 clock_boottime_or_monotonic(),
1076 lifetime_timeout, 10 * USEC_PER_MSEC,
1077 client_timeout_expire, client);
1081 r = sd_event_source_set_priority(client->timeout_expire,
1082 client->event_priority);
1086 log_dhcp_client(client, "lease expires in %s",
1087 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1088 lifetime_timeout - time_now, 0));
1090 /* don't arm earlier timeouts if this has already expired */
1091 if (lifetime_timeout <= time_now)
1094 /* arm T2 timeout */
1095 r = sd_event_add_time(client->event,
1096 &client->timeout_t2,
1097 clock_boottime_or_monotonic(),
1100 client_timeout_t2, client);
1104 r = sd_event_source_set_priority(client->timeout_t2,
1105 client->event_priority);
1109 log_dhcp_client(client, "T2 expires in %s",
1110 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1111 t2_timeout - time_now, 0));
1113 /* don't arm earlier timeout if this has already expired */
1114 if (t2_timeout <= time_now)
1117 /* arm T1 timeout */
1118 r = sd_event_add_time(client->event,
1119 &client->timeout_t1,
1120 clock_boottime_or_monotonic(),
1121 t1_timeout, 10 * USEC_PER_MSEC,
1122 client_timeout_t1, client);
1126 r = sd_event_source_set_priority(client->timeout_t1,
1127 client->event_priority);
1131 log_dhcp_client(client, "T1 expires in %s",
1132 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1133 t1_timeout - time_now, 0));
1138 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1140 DHCP_CLIENT_DONT_DESTROY(client);
1141 int r = 0, notify_event = 0;
1144 assert(client->event);
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,
1161 clock_boottime_or_monotonic(),
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);
1184 client->timeout_resend =
1185 sd_event_source_unref(client->timeout_resend);
1187 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1188 DHCP_STATE_REBOOTING))
1189 notify_event = DHCP_EVENT_IP_ACQUIRE;
1190 else if (r != DHCP_EVENT_IP_ACQUIRE)
1193 client->state = DHCP_STATE_BOUND;
1194 client->attempt = 1;
1196 client->last_addr = client->lease->address;
1198 r = client_set_lease_timeouts(client);
1202 r = dhcp_network_bind_udp_socket(client->lease->address,
1205 log_dhcp_client(client, "could not bind UDP socket");
1211 client_initialize_io_events(client, client_receive_message_udp);
1214 client_notify(client, notify_event);
1215 if (client->state == DHCP_STATE_STOPPED)
1219 } else if (r == -EADDRNOTAVAIL) {
1220 /* got a NAK, let's restart the client */
1221 client->timeout_resend =
1222 sd_event_source_unref(client->timeout_resend);
1224 r = client_initialize(client);
1228 r = client_start(client);
1232 log_dhcp_client(client, "REBOOTED");
1235 } else if (r == -ENOMSG)
1236 /* invalid message, let's ignore it */
1241 case DHCP_STATE_BOUND:
1242 r = client_handle_forcerenew(client, message, len);
1244 r = client_timeout_t1(NULL, 0, client);
1247 } else if (r == -ENOMSG)
1248 /* invalid message, let's ignore it */
1253 case DHCP_STATE_INIT:
1254 case DHCP_STATE_INIT_REBOOT:
1258 case DHCP_STATE_STOPPED:
1265 client_stop(client, r);
1270 static int client_receive_message_udp(sd_event_source *s, int fd,
1271 uint32_t revents, void *userdata) {
1272 sd_dhcp_client *client = userdata;
1273 _cleanup_free_ DHCPMessage *message = NULL;
1274 int buflen = 0, len, r;
1279 r = ioctl(fd, FIONREAD, &buflen);
1284 /* this can't be right */
1287 message = malloc0(buflen);
1291 len = read(fd, message, buflen);
1293 log_dhcp_client(client, "could not receive message from UDP "
1296 } else if ((size_t)len < sizeof(DHCPMessage)) {
1297 log_dhcp_client(client, "too small to be a DHCP message: ignoring");
1301 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1302 log_dhcp_client(client, "not a DHCP message: ignoring");
1306 if (message->op != BOOTREPLY) {
1307 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1311 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1312 log_dhcp_client(client, "not an ethernet packet");
1316 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1318 log_dhcp_client(client, "received chaddr does not match "
1319 "expected: ignoring");
1323 if (client->state != DHCP_STATE_BOUND &&
1324 be32toh(message->xid) != client->xid) {
1325 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1326 so ignore the xid in this case */
1327 log_dhcp_client(client, "received xid (%u) does not match "
1328 "expected (%u): ignoring",
1329 be32toh(message->xid), client->xid);
1333 return client_handle_message(client, message, len);
1336 static int client_receive_message_raw(sd_event_source *s, int fd,
1337 uint32_t revents, void *userdata) {
1338 sd_dhcp_client *client = userdata;
1339 _cleanup_free_ DHCPPacket *packet = NULL;
1340 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1341 struct iovec iov = {};
1342 struct msghdr msg = {
1345 .msg_control = cmsgbuf,
1346 .msg_controllen = sizeof(cmsgbuf),
1348 struct cmsghdr *cmsg;
1349 bool checksum = true;
1350 int buflen = 0, len, r;
1355 r = ioctl(fd, FIONREAD, &buflen);
1360 /* this can't be right */
1363 packet = malloc0(buflen);
1367 iov.iov_base = packet;
1368 iov.iov_len = buflen;
1370 len = recvmsg(fd, &msg, 0);
1372 log_dhcp_client(client, "could not receive message from raw "
1375 } else if ((size_t)len < sizeof(DHCPPacket))
1378 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1379 if (cmsg->cmsg_level == SOL_PACKET &&
1380 cmsg->cmsg_type == PACKET_AUXDATA &&
1381 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1382 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1384 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1389 r = dhcp_packet_verify_headers(packet, len, checksum);
1393 len -= DHCP_IP_UDP_SIZE;
1395 return client_handle_message(client, &packet->dhcp, len);
1398 int sd_dhcp_client_start(sd_dhcp_client *client) {
1401 assert_return(client, -EINVAL);
1403 r = client_initialize(client);
1407 if (client->last_addr)
1408 client->state = DHCP_STATE_INIT_REBOOT;
1410 r = client_start(client);
1412 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1414 ether_ntoa(&client->client_id.mac_addr));
1419 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1420 DHCP_CLIENT_DONT_DESTROY(client);
1422 assert_return(client, -EINVAL);
1424 client_stop(client, DHCP_EVENT_STOP);
1425 client->state = DHCP_STATE_STOPPED;
1430 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1434 assert_return(client, -EINVAL);
1435 assert_return(!client->event, -EBUSY);
1438 client->event = sd_event_ref(event);
1440 r = sd_event_default(&client->event);
1445 client->event_priority = priority;
1450 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1451 assert_return(client, -EINVAL);
1453 client->event = sd_event_unref(client->event);
1458 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1462 return client->event;
1465 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1467 assert_se(REFCNT_INC(client->n_ref) >= 2);
1472 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1473 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1474 log_dhcp_client(client, "FREE");
1476 client_initialize(client);
1478 client->receive_message =
1479 sd_event_source_unref(client->receive_message);
1481 sd_dhcp_client_detach_event(client);
1483 sd_dhcp_lease_unref(client->lease);
1485 free(client->req_opts);
1486 free(client->hostname);
1487 free(client->vendor_class_identifier);
1494 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1495 _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1497 assert_return(ret, -EINVAL);
1499 client = new0(sd_dhcp_client, 1);
1503 client->n_ref = REFCNT_INIT;
1504 client->state = DHCP_STATE_INIT;
1507 client->attempt = 1;
1509 client->req_opts_size = ELEMENTSOF(default_req_opts);
1511 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1512 if (!client->req_opts)