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 <linux/if_infiniband.h>
27 #include <netinet/ether.h>
28 #include <sys/param.h>
29 #include <sys/ioctl.h>
36 #include "dhcp-protocol.h"
37 #include "dhcp-internal.h"
38 #include "dhcp-lease-internal.h"
39 #include "sd-dhcp-client.h"
41 #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
43 struct sd_dhcp_client {
49 sd_event_source *timeout_resend;
52 union sockaddr_union link;
53 sd_event_source *receive_message;
54 bool request_broadcast;
56 size_t req_opts_allocated;
61 struct ether_addr mac_addr;
63 uint8_t mac_addr[MAX_MAC_ADDR_LEN];
67 char *vendor_class_identifier;
74 sd_event_source *timeout_t1;
75 sd_event_source *timeout_t2;
76 sd_event_source *timeout_expire;
77 sd_dhcp_client_cb_t cb;
82 static const uint8_t default_req_opts[] = {
83 DHCP_OPTION_SUBNET_MASK,
85 DHCP_OPTION_HOST_NAME,
86 DHCP_OPTION_DOMAIN_NAME,
87 DHCP_OPTION_DOMAIN_NAME_SERVER,
88 DHCP_OPTION_NTP_SERVER,
91 static int client_receive_message_raw(sd_event_source *s, int fd,
92 uint32_t revents, void *userdata);
93 static int client_receive_message_udp(sd_event_source *s, int fd,
94 uint32_t revents, void *userdata);
95 static void client_stop(sd_dhcp_client *client, int error);
97 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
99 assert_return(client, -EINVAL);
102 client->userdata = userdata;
107 int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
108 assert_return(client, -EINVAL);
110 client->request_broadcast = !!broadcast;
115 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
118 assert_return(client, -EINVAL);
119 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
120 DHCP_STATE_STOPPED), -EBUSY);
123 case DHCP_OPTION_PAD:
124 case DHCP_OPTION_OVERLOAD:
125 case DHCP_OPTION_MESSAGE_TYPE:
126 case DHCP_OPTION_PARAMETER_REQUEST_LIST:
127 case DHCP_OPTION_END:
134 for (i = 0; i < client->req_opts_size; i++)
135 if (client->req_opts[i] == option)
138 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
139 client->req_opts_size + 1))
142 client->req_opts[client->req_opts_size++] = option;
147 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
148 const struct in_addr *last_addr) {
149 assert_return(client, -EINVAL);
150 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
151 DHCP_STATE_STOPPED), -EBUSY);
154 client->last_addr = last_addr->s_addr;
156 client->last_addr = INADDR_ANY;
161 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
162 assert_return(client, -EINVAL);
163 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
164 DHCP_STATE_STOPPED), -EBUSY);
165 assert_return(interface_index > 0, -EINVAL);
167 client->index = interface_index;
172 int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
173 size_t addr_len, uint16_t arp_type) {
174 DHCP_CLIENT_DONT_DESTROY(client);
175 bool need_restart = false;
177 assert_return(client, -EINVAL);
178 assert_return(addr, -EINVAL);
179 assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
180 assert_return(arp_type > 0, -EINVAL);
182 if (arp_type == ARPHRD_ETHER)
183 assert_return(addr_len == ETH_ALEN, -EINVAL);
184 else if (arp_type == ARPHRD_INFINIBAND)
185 assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
189 if (client->mac_addr_len == addr_len &&
190 memcmp(&client->mac_addr, addr, addr_len) == 0)
193 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
194 log_dhcp_client(client, "Changing MAC address on running DHCP "
195 "client, restarting");
197 client_stop(client, DHCP_EVENT_STOP);
200 memcpy(&client->mac_addr, addr, addr_len);
201 client->mac_addr_len = addr_len;
202 client->arp_type = arp_type;
204 memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
205 client->client_id.type = 0x01;
207 if (need_restart && client->state != DHCP_STATE_STOPPED)
208 sd_dhcp_client_start(client);
213 int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
214 const char *hostname) {
215 char *new_hostname = NULL;
217 assert_return(client, -EINVAL);
219 if (streq_ptr(client->hostname, hostname))
223 new_hostname = strdup(hostname);
228 free(client->hostname);
229 client->hostname = new_hostname;
234 int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client,
236 char *new_vci = NULL;
238 assert_return(client, -EINVAL);
240 new_vci = strdup(vci);
244 free(client->vendor_class_identifier);
246 client->vendor_class_identifier = new_vci;
251 int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
252 assert_return(client, -EINVAL);
253 assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
260 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
261 assert_return(client, -EINVAL);
262 assert_return(ret, -EINVAL);
264 if (client->state != DHCP_STATE_BOUND &&
265 client->state != DHCP_STATE_RENEWING &&
266 client->state != DHCP_STATE_REBINDING)
267 return -EADDRNOTAVAIL;
269 *ret = sd_dhcp_lease_ref(client->lease);
274 static void client_notify(sd_dhcp_client *client, int event) {
276 client->cb(client, event, client->userdata);
279 static int client_initialize(sd_dhcp_client *client) {
280 assert_return(client, -EINVAL);
282 client->receive_message =
283 sd_event_source_unref(client->receive_message);
285 client->fd = asynchronous_close(client->fd);
287 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
289 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
290 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
291 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
295 client->state = DHCP_STATE_INIT;
299 client->lease = sd_dhcp_lease_unref(client->lease);
304 static void client_stop(sd_dhcp_client *client, int error) {
308 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
309 else if (error == DHCP_EVENT_STOP)
310 log_dhcp_client(client, "STOPPED");
312 log_dhcp_client(client, "STOPPED: Unknown event");
314 client_notify(client, error);
316 client_initialize(client);
319 static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
320 uint8_t type, size_t *_optlen, size_t *_optoffset) {
321 _cleanup_free_ DHCPPacket *packet;
322 size_t optlen, optoffset, size;
327 assert(client->secs);
331 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
333 optlen = DHCP_MIN_OPTIONS_SIZE;
334 size = sizeof(DHCPPacket) + optlen;
336 packet = malloc0(size);
340 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
341 client->arp_type, optlen, &optoffset);
345 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
346 refuse to issue an DHCP lease if 'secs' is set to zero */
347 packet->dhcp.secs = htobe16(client->secs);
349 /* RFC2132 section 4.1
350 A client that cannot receive unicast IP datagrams until its protocol
351 software has been configured with an IP address SHOULD set the
352 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
353 DHCPREQUEST messages that client sends. The BROADCAST bit will
354 provide a hint to the DHCP server and BOOTP relay agent to broadcast
355 any messages to the client on the client's subnet.
357 Note: some interfaces needs this to be enabled, but some networks
358 needs this to be disabled as broadcasts are filteretd, so this
359 needs to be configurable */
360 if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
361 packet->dhcp.flags = htobe16(0x8000);
363 /* RFC2132 section 4.1.1:
364 The client MUST include its hardware address in the ’chaddr’ field, if
365 necessary for delivery of DHCP reply messages. Non-Ethernet
366 interfaces will leave 'chaddr' empty and use the client identifier
367 instead (eg, RFC 4390 section 2.1).
369 if (client->arp_type == ARPHRD_ETHER)
370 memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
372 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
373 Identifier option is not set */
374 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
375 DHCP_OPTION_CLIENT_IDENTIFIER,
376 sizeof(client->client_id), &client->client_id);
381 /* RFC2131 section 3.5:
382 in its initial DHCPDISCOVER or DHCPREQUEST message, a
383 client may provide the server with a list of specific
384 parameters the client is interested in. If the client
385 includes a list of parameters in a DHCPDISCOVER message,
386 it MUST include that list in any subsequent DHCPREQUEST
389 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
390 DHCP_OPTION_PARAMETER_REQUEST_LIST,
391 client->req_opts_size, client->req_opts);
395 /* RFC2131 section 3.5:
396 The client SHOULD include the ’maximum DHCP message size’ option to
397 let the server know how large the server may make its DHCP messages.
399 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
400 than the defined default size unless the Maximum Messge Size option
403 RFC3442 "Requirements to Avoid Sizing Constraints":
404 Because a full routing table can be quite large, the standard 576
405 octet maximum size for a DHCP message may be too short to contain
406 some legitimate Classless Static Route options. Because of this,
407 clients implementing the Classless Static Route option SHOULD send a
408 Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
409 stack is capable of receiving larger IP datagrams. In this case, the
410 client SHOULD set the value of this option to at least the MTU of the
411 interface that the client is configuring. The client MAY set the
412 value of this option higher, up to the size of the largest UDP packet
413 it is prepared to accept. (Note that the value specified in the
414 Maximum DHCP Message Size option is the total maximum packet size,
415 including IP and UDP headers.)
417 max_size = htobe16(size);
418 r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
419 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
425 *_optoffset = optoffset;
432 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
434 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
435 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
437 return dhcp_network_send_raw_socket(client->fd, &client->link,
441 static int client_send_discover(sd_dhcp_client *client) {
442 _cleanup_free_ DHCPPacket *discover = NULL;
443 size_t optoffset, optlen;
448 assert(client->state == DHCP_STATE_INIT ||
449 client->state == DHCP_STATE_SELECTING);
451 /* See RFC2131 section 4.4.1 */
453 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
456 assert(time_now >= client->start_time);
458 /* seconds between sending first and last DISCOVER
459 * must always be strictly positive to deal with broken servers */
460 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
462 r = client_message_init(client, &discover, DHCP_DISCOVER,
463 &optlen, &optoffset);
467 /* the client may suggest values for the network address
468 and lease time in the DHCPDISCOVER message. The client may include
469 the ’requested IP address’ option to suggest that a particular IP
470 address be assigned, and may include the ’IP address lease time’
471 option to suggest the lease time it would like.
473 if (client->last_addr != INADDR_ANY) {
474 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
475 DHCP_OPTION_REQUESTED_IP_ADDRESS,
476 4, &client->last_addr);
481 /* it is unclear from RFC 2131 if client should send hostname in
482 DHCPDISCOVER but dhclient does and so we do as well
484 if (client->hostname) {
485 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
486 DHCP_OPTION_HOST_NAME,
487 strlen(client->hostname), client->hostname);
492 if (client->vendor_class_identifier) {
493 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
494 DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
495 strlen(client->vendor_class_identifier),
496 client->vendor_class_identifier);
501 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
502 DHCP_OPTION_END, 0, NULL);
506 /* We currently ignore:
507 The client SHOULD wait a random time between one and ten seconds to
508 desynchronize the use of DHCP at startup.
510 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
514 log_dhcp_client(client, "DISCOVER");
519 static int client_send_request(sd_dhcp_client *client) {
520 _cleanup_free_ DHCPPacket *request = NULL;
521 size_t optoffset, optlen;
524 r = client_message_init(client, &request, DHCP_REQUEST,
525 &optlen, &optoffset);
529 switch (client->state) {
530 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
531 SELECTING should be REQUESTING)
534 case DHCP_STATE_REQUESTING:
535 /* Client inserts the address of the selected server in ’server
536 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
537 filled in with the yiaddr value from the chosen DHCPOFFER.
540 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
541 DHCP_OPTION_SERVER_IDENTIFIER,
542 4, &client->lease->server_address);
546 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
547 DHCP_OPTION_REQUESTED_IP_ADDRESS,
548 4, &client->lease->address);
554 case DHCP_STATE_INIT_REBOOT:
555 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
556 option MUST be filled in with client’s notion of its previously
557 assigned address. ’ciaddr’ MUST be zero.
559 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
560 DHCP_OPTION_REQUESTED_IP_ADDRESS,
561 4, &client->last_addr);
566 case DHCP_STATE_RENEWING:
567 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
568 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
569 client’s IP address.
573 case DHCP_STATE_REBINDING:
574 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
575 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
576 client’s IP address.
578 This message MUST be broadcast to the 0xffffffff IP broadcast address.
580 request->dhcp.ciaddr = client->lease->address;
584 case DHCP_STATE_INIT:
585 case DHCP_STATE_SELECTING:
586 case DHCP_STATE_REBOOTING:
587 case DHCP_STATE_BOUND:
588 case DHCP_STATE_STOPPED:
592 if (client->hostname) {
593 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
594 DHCP_OPTION_HOST_NAME,
595 strlen(client->hostname), client->hostname);
600 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
601 DHCP_OPTION_END, 0, NULL);
605 if (client->state == DHCP_STATE_RENEWING) {
606 r = dhcp_network_send_udp_socket(client->fd,
607 client->lease->server_address,
610 sizeof(DHCPMessage) + optoffset);
612 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
617 switch (client->state) {
618 case DHCP_STATE_REQUESTING:
619 log_dhcp_client(client, "REQUEST (requesting)");
621 case DHCP_STATE_INIT_REBOOT:
622 log_dhcp_client(client, "REQUEST (init-reboot)");
624 case DHCP_STATE_RENEWING:
625 log_dhcp_client(client, "REQUEST (renewing)");
627 case DHCP_STATE_REBINDING:
628 log_dhcp_client(client, "REQUEST (rebinding)");
631 log_dhcp_client(client, "REQUEST (invalid)");
638 static int client_start(sd_dhcp_client *client);
640 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
642 sd_dhcp_client *client = userdata;
643 DHCP_CLIENT_DONT_DESTROY(client);
644 usec_t next_timeout = 0;
651 assert(client->event);
653 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
657 switch (client->state) {
658 case DHCP_STATE_RENEWING:
660 time_left = (client->lease->t2 - client->lease->t1) / 2;
664 next_timeout = time_now + time_left * USEC_PER_SEC;
668 case DHCP_STATE_REBINDING:
670 time_left = (client->lease->lifetime - client->lease->t2) / 2;
674 next_timeout = time_now + time_left * USEC_PER_SEC;
677 case DHCP_STATE_REBOOTING:
678 /* start over as we did not receive a timely ack or nak */
679 r = client_initialize(client);
683 r = client_start(client);
687 log_dhcp_client(client, "REBOOTED");
691 case DHCP_STATE_INIT:
692 case DHCP_STATE_INIT_REBOOT:
693 case DHCP_STATE_SELECTING:
694 case DHCP_STATE_REQUESTING:
695 case DHCP_STATE_BOUND:
697 if (client->attempt < 64)
698 client->attempt *= 2;
700 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
704 case DHCP_STATE_STOPPED:
709 next_timeout += (random_u32() & 0x1fffff);
711 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
713 r = sd_event_add_time(client->event,
714 &client->timeout_resend,
715 clock_boottime_or_monotonic(),
716 next_timeout, 10 * USEC_PER_MSEC,
717 client_timeout_resend, client);
721 r = sd_event_source_set_priority(client->timeout_resend,
722 client->event_priority);
726 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
730 switch (client->state) {
731 case DHCP_STATE_INIT:
732 r = client_send_discover(client);
734 client->state = DHCP_STATE_SELECTING;
737 if (client->attempt >= 64)
743 case DHCP_STATE_SELECTING:
744 r = client_send_discover(client);
745 if (r < 0 && client->attempt >= 64)
750 case DHCP_STATE_INIT_REBOOT:
751 case DHCP_STATE_REQUESTING:
752 case DHCP_STATE_RENEWING:
753 case DHCP_STATE_REBINDING:
754 r = client_send_request(client);
755 if (r < 0 && client->attempt >= 64)
758 if (client->state == DHCP_STATE_INIT_REBOOT)
759 client->state = DHCP_STATE_REBOOTING;
761 client->request_sent = time_now;
765 case DHCP_STATE_REBOOTING:
766 case DHCP_STATE_BOUND:
770 case DHCP_STATE_STOPPED:
778 client_stop(client, r);
780 /* Errors were dealt with when stopping the client, don't spill
781 errors into the event loop handler */
785 static int client_initialize_io_events(sd_dhcp_client *client,
786 sd_event_io_handler_t io_callback) {
790 assert(client->event);
792 r = sd_event_add_io(client->event, &client->receive_message,
793 client->fd, EPOLLIN, io_callback,
798 r = sd_event_source_set_priority(client->receive_message,
799 client->event_priority);
803 r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
809 client_stop(client, r);
814 static int client_initialize_time_events(sd_dhcp_client *client) {
818 assert(client->event);
820 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
822 r = sd_event_add_time(client->event,
823 &client->timeout_resend,
824 clock_boottime_or_monotonic(),
826 client_timeout_resend, client);
830 r = sd_event_source_set_priority(client->timeout_resend,
831 client->event_priority);
833 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
839 client_stop(client, r);
845 static int client_initialize_events(sd_dhcp_client *client,
846 sd_event_io_handler_t io_callback) {
847 client_initialize_io_events(client, io_callback);
848 client_initialize_time_events(client);
853 static int client_start(sd_dhcp_client *client) {
856 assert_return(client, -EINVAL);
857 assert_return(client->event, -EINVAL);
858 assert_return(client->index > 0, -EINVAL);
859 assert_return(client->fd < 0, -EBUSY);
860 assert_return(client->xid == 0, -EINVAL);
861 assert_return(client->state == DHCP_STATE_INIT ||
862 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
864 client->xid = random_u32();
866 r = dhcp_network_bind_raw_socket(client->index, &client->link,
867 client->xid, client->mac_addr,
868 client->mac_addr_len, client->arp_type);
870 client_stop(client, r);
875 if (client->state == DHCP_STATE_INIT) {
876 client->start_time = now(clock_boottime_or_monotonic());
880 return client_initialize_events(client, client_receive_message_raw);
883 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
885 sd_dhcp_client *client = userdata;
886 DHCP_CLIENT_DONT_DESTROY(client);
888 log_dhcp_client(client, "EXPIRED");
890 client_notify(client, DHCP_EVENT_EXPIRED);
892 /* lease was lost, start over if not freed or stopped in callback */
893 if (client->state != DHCP_STATE_STOPPED) {
894 client_initialize(client);
895 client_start(client);
901 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
902 sd_dhcp_client *client = userdata;
903 DHCP_CLIENT_DONT_DESTROY(client);
906 client->receive_message = sd_event_source_unref(client->receive_message);
907 client->fd = asynchronous_close(client->fd);
909 client->state = DHCP_STATE_REBINDING;
912 r = dhcp_network_bind_raw_socket(client->index, &client->link,
913 client->xid, client->mac_addr,
914 client->mac_addr_len, client->arp_type);
916 client_stop(client, r);
921 return client_initialize_events(client, client_receive_message_raw);
924 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
926 sd_dhcp_client *client = userdata;
927 DHCP_CLIENT_DONT_DESTROY(client);
929 client->state = DHCP_STATE_RENEWING;
932 return client_initialize_time_events(client);
935 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
937 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
940 r = dhcp_lease_new(&lease);
944 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
945 if (r != DHCP_OFFER) {
946 log_dhcp_client(client, "received message was not an OFFER, ignoring");
950 lease->next_server = offer->siaddr;
952 lease->address = offer->yiaddr;
954 if (lease->address == INADDR_ANY ||
955 lease->server_address == INADDR_ANY ||
956 lease->lifetime == 0) {
957 log_dhcp_client(client, "received lease lacks address, server "
958 "address or lease lifetime, ignoring");
962 if (lease->subnet_mask == INADDR_ANY) {
963 r = dhcp_lease_set_default_subnet_mask(lease);
965 log_dhcp_client(client, "received lease lacks subnet "
966 "mask, and a fallback one can not be "
967 "generated, ignoring");
972 sd_dhcp_lease_unref(client->lease);
973 client->lease = lease;
976 log_dhcp_client(client, "OFFER");
981 static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
985 r = dhcp_option_parse(force, len, NULL, NULL);
986 if (r != DHCP_FORCERENEW)
989 log_dhcp_client(client, "FORCERENEW");
994 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
996 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
999 r = dhcp_lease_new(&lease);
1003 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
1004 if (r == DHCP_NAK) {
1005 log_dhcp_client(client, "NAK");
1006 return -EADDRNOTAVAIL;
1009 if (r != DHCP_ACK) {
1010 log_dhcp_client(client, "received message was not an ACK, ignoring");
1014 lease->next_server = ack->siaddr;
1016 lease->address = ack->yiaddr;
1018 if (lease->address == INADDR_ANY ||
1019 lease->server_address == INADDR_ANY ||
1020 lease->lifetime == 0) {
1021 log_dhcp_client(client, "received lease lacks address, server "
1022 "address or lease lifetime, ignoring");
1026 if (lease->subnet_mask == INADDR_ANY) {
1027 r = dhcp_lease_set_default_subnet_mask(lease);
1029 log_dhcp_client(client, "received lease lacks subnet "
1030 "mask, and a fallback one can not be "
1031 "generated, ignoring");
1036 r = DHCP_EVENT_IP_ACQUIRE;
1037 if (client->lease) {
1038 if (client->lease->address != lease->address ||
1039 client->lease->subnet_mask != lease->subnet_mask ||
1040 client->lease->router != lease->router) {
1041 r = DHCP_EVENT_IP_CHANGE;
1043 r = DHCP_EVENT_RENEW;
1045 client->lease = sd_dhcp_lease_unref(client->lease);
1048 client->lease = lease;
1051 log_dhcp_client(client, "ACK");
1056 static uint64_t client_compute_timeout(sd_dhcp_client *client,
1057 uint32_t lifetime, double factor) {
1059 assert(client->request_sent);
1062 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
1063 + (random_u32() & 0x1fffff);
1066 static int client_set_lease_timeouts(sd_dhcp_client *client) {
1068 uint64_t lifetime_timeout;
1069 uint64_t t2_timeout;
1070 uint64_t t1_timeout;
1071 char time_string[FORMAT_TIMESPAN_MAX];
1075 assert(client->event);
1076 assert(client->lease);
1077 assert(client->lease->lifetime);
1079 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1080 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1081 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
1083 /* don't set timers for infinite leases */
1084 if (client->lease->lifetime == 0xffffffff)
1087 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1090 assert(client->request_sent <= time_now);
1092 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1093 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
1094 if (client->lease->t1 && client->lease->t2) {
1095 /* both T1 and T2 are given */
1096 if (client->lease->t1 < client->lease->t2 &&
1097 client->lease->t2 < client->lease->lifetime) {
1098 /* they are both valid */
1099 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1100 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1103 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1104 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1105 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1106 client->lease->t1 = client->lease->lifetime / 2;
1108 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
1109 /* only T2 is given, and it is valid */
1110 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1111 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1112 client->lease->t1 = client->lease->lifetime / 2;
1113 if (t2_timeout <= t1_timeout) {
1114 /* the computed T1 would be invalid, so discard T2 */
1115 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1116 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1118 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
1119 /* only T1 is given, and it is valid */
1120 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1121 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1122 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1123 if (t2_timeout <= t1_timeout) {
1124 /* the computed T2 would be invalid, so discard T1 */
1125 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1126 client->lease->t2 = client->lease->lifetime / 2;
1129 /* fall back to the default timeouts */
1130 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1131 client->lease->t1 = client->lease->lifetime / 2;
1132 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1133 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1136 /* arm lifetime timeout */
1137 r = sd_event_add_time(client->event, &client->timeout_expire,
1138 clock_boottime_or_monotonic(),
1139 lifetime_timeout, 10 * USEC_PER_MSEC,
1140 client_timeout_expire, client);
1144 r = sd_event_source_set_priority(client->timeout_expire,
1145 client->event_priority);
1149 r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime");
1153 log_dhcp_client(client, "lease expires in %s",
1154 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1155 lifetime_timeout - time_now, 0));
1157 /* don't arm earlier timeouts if this has already expired */
1158 if (lifetime_timeout <= time_now)
1161 /* arm T2 timeout */
1162 r = sd_event_add_time(client->event,
1163 &client->timeout_t2,
1164 clock_boottime_or_monotonic(),
1167 client_timeout_t2, client);
1171 r = sd_event_source_set_priority(client->timeout_t2,
1172 client->event_priority);
1176 r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout");
1180 log_dhcp_client(client, "T2 expires in %s",
1181 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1182 t2_timeout - time_now, 0));
1184 /* don't arm earlier timeout if this has already expired */
1185 if (t2_timeout <= time_now)
1188 /* arm T1 timeout */
1189 r = sd_event_add_time(client->event,
1190 &client->timeout_t1,
1191 clock_boottime_or_monotonic(),
1192 t1_timeout, 10 * USEC_PER_MSEC,
1193 client_timeout_t1, client);
1197 r = sd_event_source_set_priority(client->timeout_t1,
1198 client->event_priority);
1202 r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer");
1206 log_dhcp_client(client, "T1 expires in %s",
1207 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1208 t1_timeout - time_now, 0));
1213 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1215 DHCP_CLIENT_DONT_DESTROY(client);
1216 int r = 0, notify_event = 0;
1219 assert(client->event);
1222 switch (client->state) {
1223 case DHCP_STATE_SELECTING:
1225 r = client_handle_offer(client, message, len);
1228 client->timeout_resend =
1229 sd_event_source_unref(client->timeout_resend);
1231 client->state = DHCP_STATE_REQUESTING;
1232 client->attempt = 1;
1234 r = sd_event_add_time(client->event,
1235 &client->timeout_resend,
1236 clock_boottime_or_monotonic(),
1238 client_timeout_resend, client);
1242 r = sd_event_source_set_priority(client->timeout_resend,
1243 client->event_priority);
1247 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
1250 } else if (r == -ENOMSG)
1251 /* invalid message, let's ignore it */
1256 case DHCP_STATE_REBOOTING:
1257 case DHCP_STATE_REQUESTING:
1258 case DHCP_STATE_RENEWING:
1259 case DHCP_STATE_REBINDING:
1261 r = client_handle_ack(client, message, len);
1263 client->timeout_resend =
1264 sd_event_source_unref(client->timeout_resend);
1265 client->receive_message =
1266 sd_event_source_unref(client->receive_message);
1267 client->fd = asynchronous_close(client->fd);
1269 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1270 DHCP_STATE_REBOOTING))
1271 notify_event = DHCP_EVENT_IP_ACQUIRE;
1272 else if (r != DHCP_EVENT_IP_ACQUIRE)
1275 client->state = DHCP_STATE_BOUND;
1276 client->attempt = 1;
1278 client->last_addr = client->lease->address;
1280 r = client_set_lease_timeouts(client);
1284 r = dhcp_network_bind_udp_socket(client->lease->address,
1287 log_dhcp_client(client, "could not bind UDP socket");
1293 client_initialize_io_events(client, client_receive_message_udp);
1296 client_notify(client, notify_event);
1297 if (client->state == DHCP_STATE_STOPPED)
1301 } else if (r == -EADDRNOTAVAIL) {
1302 /* got a NAK, let's restart the client */
1303 client->timeout_resend =
1304 sd_event_source_unref(client->timeout_resend);
1306 r = client_initialize(client);
1310 r = client_start(client);
1314 log_dhcp_client(client, "REBOOTED");
1317 } else if (r == -ENOMSG)
1318 /* invalid message, let's ignore it */
1323 case DHCP_STATE_BOUND:
1324 r = client_handle_forcerenew(client, message, len);
1326 r = client_timeout_t1(NULL, 0, client);
1329 } else if (r == -ENOMSG)
1330 /* invalid message, let's ignore it */
1335 case DHCP_STATE_INIT:
1336 case DHCP_STATE_INIT_REBOOT:
1340 case DHCP_STATE_STOPPED:
1347 client_stop(client, r);
1352 static int client_receive_message_udp(sd_event_source *s, int fd,
1353 uint32_t revents, void *userdata) {
1354 sd_dhcp_client *client = userdata;
1355 _cleanup_free_ DHCPMessage *message = NULL;
1356 int buflen = 0, len, r;
1357 const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
1358 const struct ether_addr *expected_chaddr = NULL;
1359 uint8_t expected_hlen = 0;
1364 r = ioctl(fd, FIONREAD, &buflen);
1369 /* this can't be right */
1372 message = malloc0(buflen);
1376 len = read(fd, message, buflen);
1378 log_dhcp_client(client, "could not receive message from UDP "
1381 } else if ((size_t)len < sizeof(DHCPMessage)) {
1382 log_dhcp_client(client, "too small to be a DHCP message: ignoring");
1386 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1387 log_dhcp_client(client, "not a DHCP message: ignoring");
1391 if (message->op != BOOTREPLY) {
1392 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1396 if (message->htype != client->arp_type) {
1397 log_dhcp_client(client, "packet type does not match client type");
1401 if (client->arp_type == ARPHRD_ETHER) {
1402 expected_hlen = ETH_ALEN;
1403 expected_chaddr = (const struct ether_addr *) &client->mac_addr;
1405 /* Non-ethernet links expect zero chaddr */
1407 expected_chaddr = &zero_mac;
1410 if (message->hlen != expected_hlen) {
1411 log_dhcp_client(client, "unexpected packet hlen %d", message->hlen);
1415 if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
1416 log_dhcp_client(client, "received chaddr does not match "
1417 "expected: ignoring");
1421 if (client->state != DHCP_STATE_BOUND &&
1422 be32toh(message->xid) != client->xid) {
1423 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1424 so ignore the xid in this case */
1425 log_dhcp_client(client, "received xid (%u) does not match "
1426 "expected (%u): ignoring",
1427 be32toh(message->xid), client->xid);
1431 return client_handle_message(client, message, len);
1434 static int client_receive_message_raw(sd_event_source *s, int fd,
1435 uint32_t revents, void *userdata) {
1436 sd_dhcp_client *client = userdata;
1437 _cleanup_free_ DHCPPacket *packet = NULL;
1438 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1439 struct iovec iov = {};
1440 struct msghdr msg = {
1443 .msg_control = cmsgbuf,
1444 .msg_controllen = sizeof(cmsgbuf),
1446 struct cmsghdr *cmsg;
1447 bool checksum = true;
1448 int buflen = 0, len, r;
1453 r = ioctl(fd, FIONREAD, &buflen);
1458 /* this can't be right */
1461 packet = malloc0(buflen);
1465 iov.iov_base = packet;
1466 iov.iov_len = buflen;
1468 len = recvmsg(fd, &msg, 0);
1470 log_dhcp_client(client, "could not receive message from raw "
1473 } else if ((size_t)len < sizeof(DHCPPacket))
1476 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1477 if (cmsg->cmsg_level == SOL_PACKET &&
1478 cmsg->cmsg_type == PACKET_AUXDATA &&
1479 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1480 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1482 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1487 r = dhcp_packet_verify_headers(packet, len, checksum);
1491 len -= DHCP_IP_UDP_SIZE;
1493 return client_handle_message(client, &packet->dhcp, len);
1496 int sd_dhcp_client_start(sd_dhcp_client *client) {
1499 assert_return(client, -EINVAL);
1501 r = client_initialize(client);
1505 if (client->last_addr)
1506 client->state = DHCP_STATE_INIT_REBOOT;
1508 r = client_start(client);
1510 log_dhcp_client(client, "STARTED on ifindex %u", client->index);
1515 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1516 DHCP_CLIENT_DONT_DESTROY(client);
1518 assert_return(client, -EINVAL);
1520 client_stop(client, DHCP_EVENT_STOP);
1521 client->state = DHCP_STATE_STOPPED;
1526 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1530 assert_return(client, -EINVAL);
1531 assert_return(!client->event, -EBUSY);
1534 client->event = sd_event_ref(event);
1536 r = sd_event_default(&client->event);
1541 client->event_priority = priority;
1546 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1547 assert_return(client, -EINVAL);
1549 client->event = sd_event_unref(client->event);
1554 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1558 return client->event;
1561 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1563 assert_se(REFCNT_INC(client->n_ref) >= 2);
1568 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1569 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1570 log_dhcp_client(client, "FREE");
1572 client_initialize(client);
1574 client->receive_message =
1575 sd_event_source_unref(client->receive_message);
1577 sd_dhcp_client_detach_event(client);
1579 sd_dhcp_lease_unref(client->lease);
1581 free(client->req_opts);
1582 free(client->hostname);
1583 free(client->vendor_class_identifier);
1590 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1591 _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1593 assert_return(ret, -EINVAL);
1595 client = new0(sd_dhcp_client, 1);
1599 client->n_ref = REFCNT_INIT;
1600 client->state = DHCP_STATE_INIT;
1603 client->attempt = 1;
1604 client->mtu = DHCP_DEFAULT_MIN_SIZE;
1606 client->req_opts_size = ELEMENTSOF(default_req_opts);
1608 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1609 if (!client->req_opts)