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: %s", strerror(-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 switch (client->state) {
484 case DHCP_STATE_REQUESTING:
485 log_dhcp_client(client, "REQUEST (requesting)");
487 case DHCP_STATE_INIT_REBOOT:
488 log_dhcp_client(client, "REQUEST (init-reboot)");
490 case DHCP_STATE_RENEWING:
491 log_dhcp_client(client, "REQUEST (renewing)");
493 case DHCP_STATE_REBINDING:
494 log_dhcp_client(client, "REQUEST (rebinding)");
497 log_dhcp_client(client, "REQUEST (invalid)");
504 static int client_start(sd_dhcp_client *client);
506 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
508 sd_dhcp_client *client = userdata;
509 usec_t next_timeout = 0;
516 assert(client->event);
518 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
522 switch (client->state) {
523 case DHCP_STATE_RENEWING:
525 time_left = (client->lease->t2 - client->lease->t1) / 2;
529 next_timeout = time_now + time_left * USEC_PER_SEC;
533 case DHCP_STATE_REBINDING:
535 time_left = (client->lease->lifetime - client->lease->t2) / 2;
539 next_timeout = time_now + time_left * USEC_PER_SEC;
542 case DHCP_STATE_REBOOTING:
543 /* start over as we did not receive a timely ack or nak */
544 r = client_initialize(client);
548 r = client_start(client);
552 log_dhcp_client(client, "REBOOTED");
556 case DHCP_STATE_INIT:
557 case DHCP_STATE_INIT_REBOOT:
558 case DHCP_STATE_SELECTING:
559 case DHCP_STATE_REQUESTING:
560 case DHCP_STATE_BOUND:
562 if (client->attempt < 64)
563 client->attempt *= 2;
565 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
569 case DHCP_STATE_STOPPED:
574 next_timeout += (random_u32() & 0x1fffff);
576 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
578 r = sd_event_add_time(client->event,
579 &client->timeout_resend,
581 next_timeout, 10 * USEC_PER_MSEC,
582 client_timeout_resend, client);
586 r = sd_event_source_set_priority(client->timeout_resend,
587 client->event_priority);
591 switch (client->state) {
592 case DHCP_STATE_INIT:
593 r = client_send_discover(client);
595 client->state = DHCP_STATE_SELECTING;
598 if (client->attempt >= 64)
604 case DHCP_STATE_SELECTING:
605 r = client_send_discover(client);
606 if (r < 0 && client->attempt >= 64)
611 case DHCP_STATE_INIT_REBOOT:
612 case DHCP_STATE_REQUESTING:
613 case DHCP_STATE_RENEWING:
614 case DHCP_STATE_REBINDING:
615 r = client_send_request(client);
616 if (r < 0 && client->attempt >= 64)
619 if (client->state == DHCP_STATE_INIT_REBOOT)
620 client->state = DHCP_STATE_REBOOTING;
622 client->request_sent = time_now;
626 case DHCP_STATE_REBOOTING:
627 case DHCP_STATE_BOUND:
631 case DHCP_STATE_STOPPED:
639 client_stop(client, r);
641 /* Errors were dealt with when stopping the client, don't spill
642 errors into the event loop handler */
646 static int client_initialize_events(sd_dhcp_client *client,
647 sd_event_io_handler_t io_callback) {
651 assert(client->event);
653 r = sd_event_add_io(client->event, &client->receive_message,
654 client->fd, EPOLLIN, io_callback,
659 r = sd_event_source_set_priority(client->receive_message,
660 client->event_priority);
664 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
666 r = sd_event_add_time(client->event,
667 &client->timeout_resend,
670 client_timeout_resend, client);
674 r = sd_event_source_set_priority(client->timeout_resend,
675 client->event_priority);
679 client_stop(client, r);
685 static int client_start(sd_dhcp_client *client) {
688 assert_return(client, -EINVAL);
689 assert_return(client->event, -EINVAL);
690 assert_return(client->index > 0, -EINVAL);
691 assert_return(client->fd < 0, -EBUSY);
692 assert_return(client->xid == 0, -EINVAL);
693 assert_return(client->state == DHCP_STATE_INIT ||
694 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
696 client->xid = random_u32();
698 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
700 client_stop(client, r);
705 if (client->state == DHCP_STATE_INIT) {
706 client->start_time = now(CLOCK_MONOTONIC);
710 return client_initialize_events(client, client_receive_message_raw);
713 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
715 sd_dhcp_client *client = userdata;
717 log_dhcp_client(client, "EXPIRED");
719 client = client_notify(client, DHCP_EVENT_EXPIRED);
721 /* lease was lost, start over if not freed or stopped in callback */
722 if (client && client->state != DHCP_STATE_STOPPED) {
723 client_initialize(client);
724 client_start(client);
730 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
731 sd_dhcp_client *client = userdata;
734 client->receive_message = sd_event_source_unref(client->receive_message);
735 client->fd = safe_close(client->fd);
737 client->state = DHCP_STATE_REBINDING;
740 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
742 client_stop(client, r);
747 return client_initialize_events(client, client_receive_message_raw);
750 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
752 sd_dhcp_client *client = userdata;
755 client->state = DHCP_STATE_RENEWING;
758 r = dhcp_network_bind_udp_socket(client->index,
759 client->lease->address,
762 client_stop(client, r);
768 return client_initialize_events(client, client_receive_message_udp);
771 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
773 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
776 r = dhcp_lease_new(&lease);
780 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
781 if (r != DHCP_OFFER) {
782 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
786 lease->next_server = offer->siaddr;
788 lease->address = offer->yiaddr;
790 if (lease->address == INADDR_ANY ||
791 lease->server_address == INADDR_ANY ||
792 lease->lifetime == 0) {
793 log_dhcp_client(client, "receieved lease lacks address, server "
794 "address or lease lifetime, ignoring");
798 if (lease->subnet_mask == INADDR_ANY) {
799 r = dhcp_lease_set_default_subnet_mask(lease);
801 log_dhcp_client(client, "receieved lease lacks subnet "
802 "mask, and a fallback one can not be "
803 "generated, ignoring");
808 sd_dhcp_lease_unref(client->lease);
809 client->lease = lease;
812 log_dhcp_client(client, "OFFER");
817 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
819 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
822 r = dhcp_lease_new(&lease);
826 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
828 log_dhcp_client(client, "NAK");
829 return DHCP_EVENT_NO_LEASE;
833 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
837 lease->next_server = ack->siaddr;
839 lease->address = ack->yiaddr;
841 if (lease->address == INADDR_ANY ||
842 lease->server_address == INADDR_ANY ||
843 lease->lifetime == 0) {
844 log_dhcp_client(client, "receieved lease lacks address, server "
845 "address or lease lifetime, ignoring");
849 if (lease->subnet_mask == INADDR_ANY) {
850 r = dhcp_lease_set_default_subnet_mask(lease);
852 log_dhcp_client(client, "receieved lease lacks subnet "
853 "mask, and a fallback one can not be "
854 "generated, ignoring");
859 r = DHCP_EVENT_IP_ACQUIRE;
861 if (client->lease->address != lease->address ||
862 client->lease->subnet_mask != lease->subnet_mask ||
863 client->lease->router != lease->router) {
864 r = DHCP_EVENT_IP_CHANGE;
867 client->lease = sd_dhcp_lease_unref(client->lease);
870 client->lease = lease;
873 log_dhcp_client(client, "ACK");
878 static uint64_t client_compute_timeout(sd_dhcp_client *client,
879 uint32_t lifetime, double factor) {
881 assert(client->request_sent);
884 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
885 + (random_u32() & 0x1fffff);
888 static int client_set_lease_timeouts(sd_dhcp_client *client) {
890 uint64_t lifetime_timeout;
893 char time_string[FORMAT_TIMESPAN_MAX];
897 assert(client->event);
898 assert(client->lease);
899 assert(client->lease->lifetime);
901 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
902 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
903 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
905 /* don't set timers for infinite leases */
906 if (client->lease->lifetime == 0xffffffff)
909 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
912 assert(client->request_sent <= time_now);
914 /* convert the various timeouts from relative (secs) to absolute (usecs) */
915 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
916 if (client->lease->t1 && client->lease->t2) {
917 /* both T1 and T2 are given */
918 if (client->lease->t1 < client->lease->t2 &&
919 client->lease->t2 < client->lease->lifetime) {
920 /* they are both valid */
921 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
922 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
925 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
926 client->lease->t2 = (client->lease->lifetime * 7) / 8;
927 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
928 client->lease->t1 = client->lease->lifetime / 2;
930 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
931 /* only T2 is given, and it is valid */
932 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
933 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
934 client->lease->t1 = client->lease->lifetime / 2;
935 if (t2_timeout <= t1_timeout) {
936 /* the computed T1 would be invalid, so discard T2 */
937 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
938 client->lease->t2 = (client->lease->lifetime * 7) / 8;
940 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
941 /* only T1 is given, and it is valid */
942 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
943 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
944 client->lease->t2 = (client->lease->lifetime * 7) / 8;
945 if (t2_timeout <= t1_timeout) {
946 /* the computed T2 would be invalid, so discard T1 */
947 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
948 client->lease->t2 = client->lease->lifetime / 2;
951 /* fall back to the default timeouts */
952 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
953 client->lease->t1 = client->lease->lifetime / 2;
954 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
955 client->lease->t2 = (client->lease->lifetime * 7) / 8;
958 /* arm lifetime timeout */
959 r = sd_event_add_time(client->event, &client->timeout_expire,
961 lifetime_timeout, 10 * USEC_PER_MSEC,
962 client_timeout_expire, client);
966 r = sd_event_source_set_priority(client->timeout_expire,
967 client->event_priority);
971 log_dhcp_client(client, "lease expires in %s",
972 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
973 lifetime_timeout - time_now, 0));
975 /* don't arm earlier timeouts if this has already expired */
976 if (lifetime_timeout <= time_now)
980 r = sd_event_add_time(client->event,
985 client_timeout_t2, client);
989 r = sd_event_source_set_priority(client->timeout_t2,
990 client->event_priority);
994 log_dhcp_client(client, "T2 expires in %s",
995 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
996 t2_timeout - time_now, 0));
998 /* don't arm earlier timeout if this has already expired */
999 if (t2_timeout <= time_now)
1002 /* arm T1 timeout */
1003 r = sd_event_add_time(client->event,
1004 &client->timeout_t1,
1006 t1_timeout, 10 * USEC_PER_MSEC,
1007 client_timeout_t1, client);
1011 r = sd_event_source_set_priority(client->timeout_t1,
1012 client->event_priority);
1016 log_dhcp_client(client, "T1 expires in %s",
1017 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1018 t1_timeout - time_now, 0));
1023 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1025 int r = 0, notify_event = 0;
1028 assert(client->event);
1031 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1032 log_dhcp_client(client, "not a DHCP message: ignoring");
1036 if (message->op != BOOTREPLY) {
1037 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1041 if (be32toh(message->xid) != client->xid) {
1042 log_dhcp_client(client, "received xid (%u) does not match "
1043 "expected (%u): ignoring",
1044 be32toh(message->xid), client->xid);
1048 if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1049 log_dhcp_client(client, "not an ethernet packet");
1053 if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1055 log_dhcp_client(client, "received chaddr does not match "
1056 "expected: ignoring");
1060 switch (client->state) {
1061 case DHCP_STATE_SELECTING:
1063 r = client_handle_offer(client, message, len);
1066 client->timeout_resend =
1067 sd_event_source_unref(client->timeout_resend);
1069 client->state = DHCP_STATE_REQUESTING;
1070 client->attempt = 1;
1072 r = sd_event_add_time(client->event,
1073 &client->timeout_resend,
1076 client_timeout_resend, client);
1080 r = sd_event_source_set_priority(client->timeout_resend,
1081 client->event_priority);
1084 } else if (r == -ENOMSG)
1085 /* invalid message, let's ignore it */
1090 case DHCP_STATE_REBOOTING:
1091 case DHCP_STATE_REQUESTING:
1092 case DHCP_STATE_RENEWING:
1093 case DHCP_STATE_REBINDING:
1095 r = client_handle_ack(client, message, len);
1096 if (r == DHCP_EVENT_NO_LEASE) {
1098 client->timeout_resend =
1099 sd_event_source_unref(client->timeout_resend);
1101 if (client->state == DHCP_STATE_REBOOTING) {
1102 r = client_initialize(client);
1106 r = client_start(client);
1110 log_dhcp_client(client, "REBOOTED");
1114 } else if (r >= 0) {
1115 client->timeout_resend =
1116 sd_event_source_unref(client->timeout_resend);
1118 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1119 DHCP_STATE_REBOOTING))
1120 notify_event = DHCP_EVENT_IP_ACQUIRE;
1121 else if (r != DHCP_EVENT_IP_ACQUIRE)
1124 client->state = DHCP_STATE_BOUND;
1125 client->attempt = 1;
1127 client->last_addr = client->lease->address;
1129 r = client_set_lease_timeouts(client);
1134 client = client_notify(client, notify_event);
1136 client->state == DHCP_STATE_STOPPED)
1140 client->receive_message =
1141 sd_event_source_unref(client->receive_message);
1142 client->fd = safe_close(client->fd);
1143 } else if (r == -ENOMSG)
1144 /* invalid message, let's ignore it */
1149 case DHCP_STATE_INIT:
1150 case DHCP_STATE_INIT_REBOOT:
1151 case DHCP_STATE_BOUND:
1155 case DHCP_STATE_STOPPED:
1161 if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1162 client_stop(client, r);
1167 static int client_receive_message_udp(sd_event_source *s, int fd,
1168 uint32_t revents, void *userdata) {
1169 sd_dhcp_client *client = userdata;
1170 _cleanup_free_ DHCPMessage *message = NULL;
1171 int buflen = 0, len, r;
1176 r = ioctl(fd, FIONREAD, &buflen);
1177 if (r < 0 || buflen <= 0)
1178 buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE;
1180 message = malloc0(buflen);
1184 len = read(fd, message, buflen);
1186 log_dhcp_client(client, "could not receive message from UDP "
1187 "socket: %s", strerror(errno));
1189 } else if ((size_t)len < sizeof(DHCPMessage))
1192 return client_handle_message(client, message, len);
1195 static int client_receive_message_raw(sd_event_source *s, int fd,
1196 uint32_t revents, void *userdata) {
1197 sd_dhcp_client *client = userdata;
1198 _cleanup_free_ DHCPPacket *packet = NULL;
1199 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1200 struct iovec iov = {};
1201 struct msghdr msg = {
1204 .msg_control = cmsgbuf,
1205 .msg_controllen = sizeof(cmsgbuf),
1207 struct cmsghdr *cmsg;
1208 bool checksum = true;
1209 int buflen = 0, len, r;
1214 r = ioctl(fd, FIONREAD, &buflen);
1215 if (r < 0 || buflen <= 0)
1216 buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE;
1218 packet = malloc0(buflen);
1222 iov.iov_base = packet;
1223 iov.iov_len = buflen;
1225 len = recvmsg(fd, &msg, 0);
1227 log_dhcp_client(client, "could not receive message from raw "
1228 "socket: %s", strerror(errno));
1230 } else if ((size_t)len < sizeof(DHCPPacket))
1233 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1234 if (cmsg->cmsg_level == SOL_PACKET &&
1235 cmsg->cmsg_type == PACKET_AUXDATA &&
1236 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1237 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1239 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1244 r = dhcp_packet_verify_headers(packet, len, checksum);
1248 len -= DHCP_IP_UDP_SIZE;
1250 return client_handle_message(client, &packet->dhcp, len);
1253 int sd_dhcp_client_start(sd_dhcp_client *client) {
1256 assert_return(client, -EINVAL);
1258 r = client_initialize(client);
1262 if (client->last_addr)
1263 client->state = DHCP_STATE_INIT_REBOOT;
1265 r = client_start(client);
1267 log_dhcp_client(client, "STARTED");
1272 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1273 assert_return(client, -EINVAL);
1275 if (client_stop(client, DHCP_EVENT_STOP))
1276 client->state = DHCP_STATE_STOPPED;
1281 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1285 assert_return(client, -EINVAL);
1286 assert_return(!client->event, -EBUSY);
1289 client->event = sd_event_ref(event);
1291 r = sd_event_default(&client->event);
1296 client->event_priority = priority;
1301 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1302 assert_return(client, -EINVAL);
1304 client->event = sd_event_unref(client->event);
1309 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1313 return client->event;
1316 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1318 assert_se(REFCNT_INC(client->n_ref) >= 2);
1323 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1324 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1325 log_dhcp_client(client, "UNREF");
1327 client_initialize(client);
1329 client->receive_message =
1330 sd_event_source_unref(client->receive_message);
1332 sd_dhcp_client_detach_event(client);
1334 sd_dhcp_lease_unref(client->lease);
1336 free(client->req_opts);
1345 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
1346 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1348 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1349 _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1351 assert_return(ret, -EINVAL);
1353 client = new0(sd_dhcp_client, 1);
1357 client->n_ref = REFCNT_INIT;
1358 client->state = DHCP_STATE_INIT;
1361 client->attempt = 1;
1363 client->req_opts_size = ELEMENTSOF(default_req_opts);
1365 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1366 if (!client->req_opts)