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 <sys/param.h>
27 #include <sys/ioctl.h>
33 #include "dhcp-protocol.h"
34 #include "dhcp-internal.h"
35 #include "dhcp-lease-internal.h"
36 #include "sd-dhcp-client.h"
38 struct sd_dhcp_client {
44 sd_event_source *timeout_resend;
47 union sockaddr_union link;
48 sd_event_source *receive_message;
50 size_t req_opts_allocated;
55 struct ether_addr mac_addr;
62 sd_event_source *timeout_t1;
63 sd_event_source *timeout_t2;
64 sd_event_source *timeout_expire;
65 sd_dhcp_client_cb_t cb;
70 static const uint8_t default_req_opts[] = {
71 DHCP_OPTION_SUBNET_MASK,
73 DHCP_OPTION_HOST_NAME,
74 DHCP_OPTION_DOMAIN_NAME,
75 DHCP_OPTION_DOMAIN_NAME_SERVER,
76 DHCP_OPTION_NTP_SERVER,
79 static int client_receive_message_raw(sd_event_source *s, int fd,
80 uint32_t revents, void *userdata);
81 static int client_receive_message_udp(sd_event_source *s, int fd,
82 uint32_t revents, void *userdata);
83 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error);
85 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
87 assert_return(client, -EINVAL);
90 client->userdata = userdata;
95 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
98 assert_return(client, -EINVAL);
99 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
100 DHCP_STATE_STOPPED), -EBUSY);
103 case DHCP_OPTION_PAD:
104 case DHCP_OPTION_OVERLOAD:
105 case DHCP_OPTION_MESSAGE_TYPE:
106 case DHCP_OPTION_PARAMETER_REQUEST_LIST:
107 case DHCP_OPTION_END:
114 for (i = 0; i < client->req_opts_size; i++)
115 if (client->req_opts[i] == option)
118 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
119 client->req_opts_size + 1))
122 client->req_opts[client->req_opts_size++] = option;
127 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
128 const struct in_addr *last_addr) {
129 assert_return(client, -EINVAL);
130 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
131 DHCP_STATE_STOPPED), -EBUSY);
134 client->last_addr = last_addr->s_addr;
136 client->last_addr = INADDR_ANY;
141 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
142 assert_return(client, -EINVAL);
143 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
144 DHCP_STATE_STOPPED), -EBUSY);
145 assert_return(interface_index >= -1, -EINVAL);
147 client->index = interface_index;
152 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
153 const struct ether_addr *addr) {
154 bool need_restart = false;
156 assert_return(client, -EINVAL);
157 assert_return(addr, -EINVAL);
159 if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
162 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
163 log_dhcp_client(client, "Changing MAC address on running DHCP "
164 "client, restarting");
166 client = client_stop(client, DHCP_EVENT_STOP);
172 memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
173 client->client_id.type = 0x01;
175 if (need_restart && client->state != DHCP_STATE_STOPPED)
176 sd_dhcp_client_start(client);
181 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
182 assert_return(client, -EINVAL);
183 assert_return(ret, -EINVAL);
185 if (client->state != DHCP_STATE_BOUND &&
186 client->state != DHCP_STATE_RENEWING &&
187 client->state != DHCP_STATE_REBINDING)
188 return -EADDRNOTAVAIL;
190 *ret = sd_dhcp_lease_ref(client->lease);
195 static sd_dhcp_client *client_notify(sd_dhcp_client *client, int event) {
197 client = sd_dhcp_client_ref(client);
198 client->cb(client, event, client->userdata);
199 client = sd_dhcp_client_unref(client);
205 static int client_initialize(sd_dhcp_client *client) {
206 assert_return(client, -EINVAL);
208 client->receive_message =
209 sd_event_source_unref(client->receive_message);
211 client->fd = safe_close(client->fd);
213 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
215 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
216 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
217 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
221 client->state = DHCP_STATE_INIT;
225 client->lease = sd_dhcp_lease_unref(client->lease);
230 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error) {
231 assert_return(client, NULL);
233 log_dhcp_client(client, "STOPPED %d", error);
235 client = client_notify(client, error);
238 client_initialize(client);
243 static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
244 uint8_t type, uint8_t **opt, size_t *optlen) {
249 assert(client->secs);
253 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
255 r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt,
260 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
261 refuse to issue an DHCP lease if 'secs' is set to zero */
262 message->secs = htobe16(client->secs);
264 /* RFC2132 section 4.1.1:
265 The client MUST include its hardware address in the ’chaddr’ field, if
266 necessary for delivery of DHCP reply messages.
268 memcpy(&message->chaddr, &client->client_id.mac_addr, ETH_ALEN);
270 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
271 Identifier option is not set */
272 r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
273 sizeof(client->client_id), &client->client_id);
278 /* RFC2131 section 3.5:
279 in its initial DHCPDISCOVER or DHCPREQUEST message, a
280 client may provide the server with a list of specific
281 parameters the client is interested in. If the client
282 includes a list of parameters in a DHCPDISCOVER message,
283 it MUST include that list in any subsequent DHCPREQUEST
286 r = dhcp_option_append(opt, optlen,
287 DHCP_OPTION_PARAMETER_REQUEST_LIST,
288 client->req_opts_size,
293 /* RFC2131 section 3.5:
294 The client SHOULD include the ’maximum DHCP message size’ option to
295 let the server know how large the server may make its DHCP messages.
297 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
298 than the defined default size unless the Maximum Messge Size option
301 max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
302 DHCP_MIN_OPTIONS_SIZE);
303 r = dhcp_option_append(opt, optlen,
304 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
312 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
314 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
315 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
317 return dhcp_network_send_raw_socket(client->fd, &client->link,
321 static int client_send_discover(sd_dhcp_client *client) {
322 _cleanup_free_ DHCPPacket *discover = NULL;
329 assert(client->state == DHCP_STATE_INIT ||
330 client->state == DHCP_STATE_SELECTING);
332 /* See RFC2131 section 4.4.1 */
334 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
337 assert(time_now >= client->start_time);
339 /* seconds between sending first and last DISCOVER
340 * must always be strictly positive to deal with broken servers */
341 client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
343 optlen = DHCP_MIN_OPTIONS_SIZE;
344 len = sizeof(DHCPPacket) + optlen;
346 discover = malloc0(len);
350 r = client_message_init(client, &discover->dhcp, DHCP_DISCOVER,
355 /* the client may suggest values for the network address
356 and lease time in the DHCPDISCOVER message. The client may include
357 the ’requested IP address’ option to suggest that a particular IP
358 address be assigned, and may include the ’IP address lease time’
359 option to suggest the lease time it would like.
361 if (client->last_addr != INADDR_ANY) {
362 r = dhcp_option_append(&opt, &optlen,
363 DHCP_OPTION_REQUESTED_IP_ADDRESS,
364 4, &client->last_addr);
369 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
373 /* We currently ignore:
374 The client SHOULD wait a random time between one and ten seconds to
375 desynchronize the use of DHCP at startup.
377 r = dhcp_client_send_raw(client, discover, len - optlen);
381 log_dhcp_client(client, "DISCOVER");
386 static int client_send_request(sd_dhcp_client *client) {
387 _cleanup_free_ DHCPPacket *request;
392 optlen = DHCP_MIN_OPTIONS_SIZE;
393 len = sizeof(DHCPPacket) + optlen;
395 request = malloc0(len);
399 r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt,
404 switch (client->state) {
405 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
406 SELECTING should be REQUESTING)
409 case DHCP_STATE_REQUESTING:
410 /* Client inserts the address of the selected server in ’server
411 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
412 filled in with the yiaddr value from the chosen DHCPOFFER.
415 r = dhcp_option_append(&opt, &optlen,
416 DHCP_OPTION_SERVER_IDENTIFIER,
417 4, &client->lease->server_address);
421 r = dhcp_option_append(&opt, &optlen,
422 DHCP_OPTION_REQUESTED_IP_ADDRESS,
423 4, &client->lease->address);
429 case DHCP_STATE_INIT_REBOOT:
430 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
431 option MUST be filled in with client’s notion of its previously
432 assigned address. ’ciaddr’ MUST be zero.
434 r = dhcp_option_append(&opt, &optlen,
435 DHCP_OPTION_REQUESTED_IP_ADDRESS,
436 4, &client->last_addr);
441 case DHCP_STATE_RENEWING:
442 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
443 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
444 client’s IP address.
448 case DHCP_STATE_REBINDING:
449 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
450 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
451 client’s IP address.
453 This message MUST be broadcast to the 0xffffffff IP broadcast address.
455 request->dhcp.ciaddr = client->lease->address;
459 case DHCP_STATE_INIT:
460 case DHCP_STATE_SELECTING:
461 case DHCP_STATE_REBOOTING:
462 case DHCP_STATE_BOUND:
463 case DHCP_STATE_STOPPED:
467 r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
471 if (client->state == DHCP_STATE_RENEWING) {
472 r = dhcp_network_send_udp_socket(client->fd,
473 client->lease->server_address,
476 len - optlen - DHCP_IP_UDP_SIZE);
478 r = dhcp_client_send_raw(client, request, len - optlen);
483 log_dhcp_client(client, "REQUEST");
488 static int client_start(sd_dhcp_client *client);
490 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
492 sd_dhcp_client *client = userdata;
493 usec_t next_timeout = 0;
500 assert(client->event);
502 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
506 switch (client->state) {
507 case DHCP_STATE_RENEWING:
509 time_left = (client->lease->t2 - client->lease->t1) / 2;
513 next_timeout = time_now + time_left * USEC_PER_SEC;
517 case DHCP_STATE_REBINDING:
519 time_left = (client->lease->lifetime - client->lease->t2) / 2;
523 next_timeout = time_now + time_left * USEC_PER_SEC;
526 case DHCP_STATE_REBOOTING:
527 /* start over as we did not receive a timely ack or nak */
528 r = client_initialize(client);
532 return client_start(client);
536 case DHCP_STATE_INIT:
537 case DHCP_STATE_INIT_REBOOT:
538 case DHCP_STATE_SELECTING:
539 case DHCP_STATE_REQUESTING:
540 case DHCP_STATE_BOUND:
542 if (client->attempt < 64)
543 client->attempt *= 2;
545 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
549 case DHCP_STATE_STOPPED:
554 next_timeout += (random_u32() & 0x1fffff);
556 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
558 r = sd_event_add_time(client->event,
559 &client->timeout_resend,
561 next_timeout, 10 * USEC_PER_MSEC,
562 client_timeout_resend, client);
566 r = sd_event_source_set_priority(client->timeout_resend,
567 client->event_priority);
571 switch (client->state) {
572 case DHCP_STATE_INIT:
573 r = client_send_discover(client);
575 client->state = DHCP_STATE_SELECTING;
578 if (client->attempt >= 64)
584 case DHCP_STATE_SELECTING:
585 r = client_send_discover(client);
586 if (r < 0 && client->attempt >= 64)
591 case DHCP_STATE_INIT_REBOOT:
592 case DHCP_STATE_REQUESTING:
593 case DHCP_STATE_RENEWING:
594 case DHCP_STATE_REBINDING:
595 r = client_send_request(client);
596 if (r < 0 && client->attempt >= 64)
599 if (client->state == DHCP_STATE_INIT_REBOOT)
600 client->state = DHCP_STATE_REBOOTING;
602 client->request_sent = time_now;
606 case DHCP_STATE_REBOOTING:
607 case DHCP_STATE_BOUND:
611 case DHCP_STATE_STOPPED:
619 client_stop(client, r);
621 /* Errors were dealt with when stopping the client, don't spill
622 errors into the event loop handler */
626 static int client_initialize_events(sd_dhcp_client *client,
627 sd_event_io_handler_t io_callback) {
631 assert(client->event);
633 r = sd_event_add_io(client->event, &client->receive_message,
634 client->fd, EPOLLIN, io_callback,
639 r = sd_event_source_set_priority(client->receive_message,
640 client->event_priority);
644 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
646 r = sd_event_add_time(client->event,
647 &client->timeout_resend,
650 client_timeout_resend, client);
654 r = sd_event_source_set_priority(client->timeout_resend,
655 client->event_priority);
659 client_stop(client, r);
665 static int client_start(sd_dhcp_client *client) {
668 assert_return(client, -EINVAL);
669 assert_return(client->event, -EINVAL);
670 assert_return(client->index > 0, -EINVAL);
671 assert_return(client->fd < 0, -EBUSY);
672 assert_return(client->xid == 0, -EINVAL);
673 assert_return(client->state == DHCP_STATE_INIT ||
674 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
676 client->xid = random_u32();
678 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
680 client_stop(client, r);
685 if (client->state == DHCP_STATE_INIT) {
686 client->start_time = now(CLOCK_MONOTONIC);
690 log_dhcp_client(client, "STARTED");
692 return client_initialize_events(client, client_receive_message_raw);
695 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
697 sd_dhcp_client *client = userdata;
699 log_dhcp_client(client, "EXPIRED");
701 client = client_notify(client, DHCP_EVENT_EXPIRED);
703 /* lease was lost, start over if not freed or stopped in callback */
704 if (client && client->state != DHCP_STATE_STOPPED) {
705 client_initialize(client);
706 client_start(client);
712 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
713 sd_dhcp_client *client = userdata;
716 client->receive_message = sd_event_source_unref(client->receive_message);
717 client->fd = safe_close(client->fd);
719 client->state = DHCP_STATE_REBINDING;
722 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
724 client_stop(client, r);
729 log_dhcp_client(client, "TIMEOUT T2");
731 return client_initialize_events(client, client_receive_message_raw);
734 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
736 sd_dhcp_client *client = userdata;
739 client->state = DHCP_STATE_RENEWING;
742 r = dhcp_network_bind_udp_socket(client->index,
743 client->lease->address,
746 client_stop(client, r);
752 log_dhcp_client(client, "TIMEOUT T1");
754 return client_initialize_events(client, client_receive_message_udp);
757 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
759 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
762 r = dhcp_lease_new(&lease);
766 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
767 if (r != DHCP_OFFER) {
768 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
772 lease->next_server = offer->siaddr;
774 lease->address = offer->yiaddr;
776 if (lease->address == INADDR_ANY ||
777 lease->server_address == INADDR_ANY ||
778 lease->lifetime == 0) {
779 log_dhcp_client(client, "receieved lease lacks address, server "
780 "address or lease lifetime, ignoring");
784 if (lease->subnet_mask == INADDR_ANY) {
785 r = dhcp_lease_set_default_subnet_mask(lease);
787 log_dhcp_client(client, "receieved lease lacks subnet "
788 "mask, and a fallback one can not be "
789 "generated, ignoring");
794 client->lease = lease;
797 log_dhcp_client(client, "OFFER");
802 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
804 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
807 r = dhcp_lease_new(&lease);
811 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
813 log_dhcp_client(client, "NAK");
814 return DHCP_EVENT_NO_LEASE;
818 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
822 lease->next_server = ack->siaddr;
824 lease->address = ack->yiaddr;
826 if (lease->address == INADDR_ANY ||
827 lease->server_address == INADDR_ANY ||
828 lease->lifetime == 0) {
829 log_dhcp_client(client, "receieved lease lacks address, server "
830 "address or lease lifetime, ignoring");
834 if (lease->subnet_mask == INADDR_ANY) {
835 r = dhcp_lease_set_default_subnet_mask(lease);
837 log_dhcp_client(client, "receieved lease lacks subnet "
838 "mask, and a fallback one can not be "
839 "generated, ignoring");
844 r = DHCP_EVENT_IP_ACQUIRE;
846 if (client->lease->address != lease->address ||
847 client->lease->subnet_mask != lease->subnet_mask ||
848 client->lease->router != lease->router) {
849 r = DHCP_EVENT_IP_CHANGE;
852 client->lease = sd_dhcp_lease_unref(client->lease);
855 client->lease = lease;
858 log_dhcp_client(client, "ACK");
863 static uint64_t client_compute_timeout(sd_dhcp_client *client,
864 uint32_t lifetime, double factor) {
866 assert(client->request_sent);
869 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
870 + (random_u32() & 0x1fffff);
873 static int client_set_lease_timeouts(sd_dhcp_client *client) {
875 uint64_t lifetime_timeout;
878 char time_string[FORMAT_TIMESPAN_MAX];
882 assert(client->event);
883 assert(client->lease);
884 assert(client->lease->lifetime);
886 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
887 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
888 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
890 /* don't set timers for infinite leases */
891 if (client->lease->lifetime == 0xffffffff)
894 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
897 assert(client->request_sent <= time_now);
899 /* convert the various timeouts from relative (secs) to absolute (usecs) */
900 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
901 if (client->lease->t1 && client->lease->t2) {
902 /* both T1 and T2 are given */
903 if (client->lease->t1 < client->lease->t2 &&
904 client->lease->t2 < client->lease->lifetime) {
905 /* they are both valid */
906 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
907 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
910 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
911 client->lease->t2 = (client->lease->lifetime * 7) / 8;
912 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
913 client->lease->t1 = client->lease->lifetime / 2;
915 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
916 /* only T2 is given, and it is valid */
917 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
918 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
919 client->lease->t1 = client->lease->lifetime / 2;
920 if (t2_timeout <= t1_timeout) {
921 /* the computed T1 would be invalid, so discard T2 */
922 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
923 client->lease->t2 = (client->lease->lifetime * 7) / 8;
925 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
926 /* only T1 is given, and it is valid */
927 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
928 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
929 client->lease->t2 = (client->lease->lifetime * 7) / 8;
930 if (t2_timeout <= t1_timeout) {
931 /* the computed T2 would be invalid, so discard T1 */
932 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
933 client->lease->t2 = client->lease->lifetime / 2;
936 /* fall back to the default timeouts */
937 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
938 client->lease->t1 = client->lease->lifetime / 2;
939 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
940 client->lease->t2 = (client->lease->lifetime * 7) / 8;
943 /* arm lifetime timeout */
944 r = sd_event_add_time(client->event, &client->timeout_expire,
946 lifetime_timeout, 10 * USEC_PER_MSEC,
947 client_timeout_expire, client);
951 r = sd_event_source_set_priority(client->timeout_expire,
952 client->event_priority);
956 log_dhcp_client(client, "lease expires in %s",
957 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
958 lifetime_timeout - time_now, 0));
960 /* don't arm earlier timeouts if this has already expired */
961 if (lifetime_timeout <= time_now)
965 r = sd_event_add_time(client->event,
970 client_timeout_t2, client);
974 r = sd_event_source_set_priority(client->timeout_t2,
975 client->event_priority);
979 log_dhcp_client(client, "T2 expires in %s",
980 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
981 t2_timeout - time_now, 0));
983 /* don't arm earlier timeout if this has already expired */
984 if (t2_timeout <= time_now)
988 r = sd_event_add_time(client->event,
991 t1_timeout, 10 * USEC_PER_MSEC,
992 client_timeout_t1, client);
996 r = sd_event_source_set_priority(client->timeout_t1,
997 client->event_priority);
1001 log_dhcp_client(client, "T1 expires in %s",
1002 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1003 t1_timeout - time_now, 0));
1008 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1010 int r = 0, notify_event = 0;
1013 assert(client->event);
1016 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1017 log_dhcp_client(client, "not a DHCP message: ignoring");
1021 if (message->op != BOOTREPLY) {
1022 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1026 if (be32toh(message->xid) != client->xid) {
1027 log_dhcp_client(client, "received xid (%u) does not match "
1028 "expected (%u): ignoring",
1029 be32toh(message->xid), client->xid);
1033 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1034 log_dhcp_client(client, "not an ethernet packet");
1038 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1040 log_dhcp_client(client, "received chaddr does not match "
1041 "expected: ignoring");
1045 switch (client->state) {
1046 case DHCP_STATE_SELECTING:
1048 r = client_handle_offer(client, message, len);
1051 client->timeout_resend =
1052 sd_event_source_unref(client->timeout_resend);
1054 client->state = DHCP_STATE_REQUESTING;
1055 client->attempt = 1;
1057 r = sd_event_add_time(client->event,
1058 &client->timeout_resend,
1061 client_timeout_resend, client);
1065 r = sd_event_source_set_priority(client->timeout_resend,
1066 client->event_priority);
1069 } else if (r == -ENOMSG)
1070 /* invalid message, let's ignore it */
1075 case DHCP_STATE_REBOOTING:
1076 case DHCP_STATE_REQUESTING:
1077 case DHCP_STATE_RENEWING:
1078 case DHCP_STATE_REBINDING:
1080 r = client_handle_ack(client, message, len);
1081 if (r == DHCP_EVENT_NO_LEASE) {
1083 client->timeout_resend =
1084 sd_event_source_unref(client->timeout_resend);
1086 if (client->state == DHCP_STATE_REBOOTING) {
1087 r = client_initialize(client);
1091 r = client_start(client);
1097 } else if (r >= 0) {
1098 client->timeout_resend =
1099 sd_event_source_unref(client->timeout_resend);
1101 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1102 DHCP_STATE_REBOOTING))
1103 notify_event = DHCP_EVENT_IP_ACQUIRE;
1104 else if (r != DHCP_EVENT_IP_ACQUIRE)
1107 client->state = DHCP_STATE_BOUND;
1108 client->attempt = 1;
1110 client->last_addr = client->lease->address;
1112 r = client_set_lease_timeouts(client);
1117 client = client_notify(client, notify_event);
1119 client->state == DHCP_STATE_STOPPED)
1123 client->receive_message =
1124 sd_event_source_unref(client->receive_message);
1125 client->fd = safe_close(client->fd);
1126 } else if (r == -ENOMSG)
1127 /* invalid message, let's ignore it */
1132 case DHCP_STATE_INIT:
1133 case DHCP_STATE_INIT_REBOOT:
1134 case DHCP_STATE_BOUND:
1138 case DHCP_STATE_STOPPED:
1144 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1145 client_stop(client, r);
1150 static int client_receive_message_udp(sd_event_source *s, int fd,
1151 uint32_t revents, void *userdata) {
1152 sd_dhcp_client *client = userdata;
1153 _cleanup_free_ DHCPMessage *message = NULL;
1154 int buflen = 0, len, r;
1159 r = ioctl(fd, FIONREAD, &buflen);
1160 if (r < 0 || buflen <= 0)
1161 buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE;
1163 message = malloc0(buflen);
1167 len = read(fd, message, buflen);
1169 log_dhcp_client(client, "could not receive message from UDP "
1170 "socket: %s", strerror(errno));
1172 } else if ((size_t)len < sizeof(DHCPMessage))
1175 return client_handle_message(client, message, len);
1178 static int client_receive_message_raw(sd_event_source *s, int fd,
1179 uint32_t revents, void *userdata) {
1180 sd_dhcp_client *client = userdata;
1181 _cleanup_free_ DHCPPacket *packet = NULL;
1182 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1183 struct iovec iov = {};
1184 struct msghdr msg = {
1187 .msg_control = cmsgbuf,
1188 .msg_controllen = sizeof(cmsgbuf),
1190 struct cmsghdr *cmsg;
1191 bool checksum = true;
1192 int buflen = 0, len, r;
1197 r = ioctl(fd, FIONREAD, &buflen);
1198 if (r < 0 || buflen <= 0)
1199 buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE;
1201 packet = malloc0(buflen);
1205 iov.iov_base = packet;
1206 iov.iov_len = buflen;
1208 len = recvmsg(fd, &msg, 0);
1210 log_dhcp_client(client, "could not receive message from raw "
1211 "socket: %s", strerror(errno));
1213 } else if ((size_t)len < sizeof(DHCPPacket))
1216 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1217 if (cmsg->cmsg_level == SOL_PACKET &&
1218 cmsg->cmsg_type == PACKET_AUXDATA &&
1219 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1220 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1222 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1227 r = dhcp_packet_verify_headers(packet, len, checksum);
1231 len -= DHCP_IP_UDP_SIZE;
1233 return client_handle_message(client, &packet->dhcp, len);
1236 int sd_dhcp_client_start(sd_dhcp_client *client) {
1239 assert_return(client, -EINVAL);
1241 r = client_initialize(client);
1245 if (client->last_addr)
1246 client->state = DHCP_STATE_INIT_REBOOT;
1248 return client_start(client);
1251 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1252 assert_return(client, -EINVAL);
1254 if (client_stop(client, DHCP_EVENT_STOP))
1255 client->state = DHCP_STATE_STOPPED;
1260 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1264 assert_return(client, -EINVAL);
1265 assert_return(!client->event, -EBUSY);
1268 client->event = sd_event_ref(event);
1270 r = sd_event_default(&client->event);
1275 client->event_priority = priority;
1280 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1281 assert_return(client, -EINVAL);
1283 client->event = sd_event_unref(client->event);
1288 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1292 return client->event;
1295 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1297 assert_se(REFCNT_INC(client->n_ref) >= 2);
1302 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1303 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1304 log_dhcp_client(client, "UNREF");
1306 client_initialize(client);
1308 client->receive_message =
1309 sd_event_source_unref(client->receive_message);
1311 sd_dhcp_client_detach_event(client);
1313 free(client->req_opts);
1322 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
1323 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1325 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1326 _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1328 assert_return(ret, -EINVAL);
1330 client = new0(sd_dhcp_client, 1);
1334 client->n_ref = REFCNT_INIT;
1335 client->state = DHCP_STATE_INIT;
1338 client->attempt = 1;
1340 client->req_opts_size = ELEMENTSOF(default_req_opts);
1342 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1343 if (!client->req_opts)