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 <sys/param.h>
30 #include "dhcp-protocol.h"
31 #include "dhcp-internal.h"
32 #include "sd-dhcp-client.h"
34 #define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
41 be32_t server_address
;
50 typedef struct DHCPLease DHCPLease
;
52 struct sd_dhcp_client
{
55 sd_event_source
*timeout_resend
;
58 union sockaddr_union link
;
59 sd_event_source
*receive_message
;
61 size_t req_opts_allocated
;
64 struct ether_addr mac_addr
;
69 sd_event_source
*timeout_t1
;
70 sd_event_source
*timeout_t2
;
71 sd_event_source
*timeout_expire
;
72 sd_dhcp_client_cb_t cb
;
77 static const uint8_t default_req_opts
[] = {
78 DHCP_OPTION_SUBNET_MASK
,
80 DHCP_OPTION_HOST_NAME
,
81 DHCP_OPTION_DOMAIN_NAME
,
82 DHCP_OPTION_DOMAIN_NAME_SERVER
,
83 DHCP_OPTION_NTP_SERVER
,
86 static int client_receive_message(sd_event_source
*s
, int fd
,
87 uint32_t revents
, void *userdata
);
89 int sd_dhcp_client_set_callback(sd_dhcp_client
*client
, sd_dhcp_client_cb_t cb
,
91 assert_return(client
, -EINVAL
);
94 client
->userdata
= userdata
;
99 int sd_dhcp_client_set_request_option(sd_dhcp_client
*client
, uint8_t option
) {
102 assert_return(client
, -EINVAL
);
103 assert_return (client
->state
== DHCP_STATE_INIT
, -EBUSY
);
106 case DHCP_OPTION_PAD
:
107 case DHCP_OPTION_OVERLOAD
:
108 case DHCP_OPTION_MESSAGE_TYPE
:
109 case DHCP_OPTION_PARAMETER_REQUEST_LIST
:
110 case DHCP_OPTION_END
:
117 for (i
= 0; i
< client
->req_opts_size
; i
++)
118 if (client
->req_opts
[i
] == option
)
121 if (!GREEDY_REALLOC(client
->req_opts
, client
->req_opts_allocated
,
122 client
->req_opts_size
+ 1))
125 client
->req_opts
[client
->req_opts_size
++] = option
;
130 int sd_dhcp_client_set_request_address(sd_dhcp_client
*client
,
131 const struct in_addr
*last_addr
) {
132 assert_return(client
, -EINVAL
);
133 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
136 client
->last_addr
= last_addr
->s_addr
;
138 client
->last_addr
= INADDR_ANY
;
143 int sd_dhcp_client_set_index(sd_dhcp_client
*client
, int interface_index
) {
144 assert_return(client
, -EINVAL
);
145 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
146 assert_return(interface_index
>= -1, -EINVAL
);
148 client
->index
= interface_index
;
153 int sd_dhcp_client_set_mac(sd_dhcp_client
*client
,
154 const struct ether_addr
*addr
) {
155 assert_return(client
, -EINVAL
);
156 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
158 memcpy(&client
->mac_addr
, addr
, ETH_ALEN
);
163 int sd_dhcp_client_get_address(sd_dhcp_client
*client
, struct in_addr
*addr
) {
164 assert_return(client
, -EINVAL
);
165 assert_return(addr
, -EINVAL
);
167 switch (client
->state
) {
168 case DHCP_STATE_INIT
:
169 case DHCP_STATE_SELECTING
:
170 case DHCP_STATE_INIT_REBOOT
:
171 case DHCP_STATE_REBOOTING
:
172 case DHCP_STATE_REQUESTING
:
173 return -EADDRNOTAVAIL
;
175 case DHCP_STATE_BOUND
:
176 case DHCP_STATE_RENEWING
:
177 case DHCP_STATE_REBINDING
:
178 addr
->s_addr
= client
->lease
->address
;
186 int sd_dhcp_client_get_mtu(sd_dhcp_client
*client
, uint16_t *mtu
) {
187 assert_return(client
, -EINVAL
);
188 assert_return(mtu
, -EINVAL
);
190 switch (client
->state
) {
191 case DHCP_STATE_INIT
:
192 case DHCP_STATE_SELECTING
:
193 case DHCP_STATE_INIT_REBOOT
:
194 case DHCP_STATE_REBOOTING
:
195 case DHCP_STATE_REQUESTING
:
196 return -EADDRNOTAVAIL
;
198 case DHCP_STATE_BOUND
:
199 case DHCP_STATE_RENEWING
:
200 case DHCP_STATE_REBINDING
:
201 if (client
->lease
->mtu
)
202 *mtu
= client
->lease
->mtu
;
212 int sd_dhcp_client_get_dns(sd_dhcp_client
*client
, struct in_addr
**addr
, size_t *addr_size
) {
213 assert_return(client
, -EINVAL
);
214 assert_return(addr
, -EINVAL
);
215 assert_return(addr_size
, -EINVAL
);
217 switch (client
->state
) {
218 case DHCP_STATE_INIT
:
219 case DHCP_STATE_SELECTING
:
220 case DHCP_STATE_INIT_REBOOT
:
221 case DHCP_STATE_REBOOTING
:
222 case DHCP_STATE_REQUESTING
:
223 return -EADDRNOTAVAIL
;
225 case DHCP_STATE_BOUND
:
226 case DHCP_STATE_RENEWING
:
227 case DHCP_STATE_REBINDING
:
228 if (client
->lease
->dns_size
) {
229 *addr_size
= client
->lease
->dns_size
;
230 *addr
= client
->lease
->dns
;
240 int sd_dhcp_client_get_hostname(sd_dhcp_client
*client
, const char **hostname
) {
241 assert_return(client
, -EINVAL
);
242 assert_return(hostname
, -EINVAL
);
244 switch (client
->state
) {
245 case DHCP_STATE_INIT
:
246 case DHCP_STATE_SELECTING
:
247 case DHCP_STATE_INIT_REBOOT
:
248 case DHCP_STATE_REBOOTING
:
249 case DHCP_STATE_REQUESTING
:
250 return -EADDRNOTAVAIL
;
252 case DHCP_STATE_BOUND
:
253 case DHCP_STATE_RENEWING
:
254 case DHCP_STATE_REBINDING
:
255 if (client
->lease
->hostname
)
256 *hostname
= client
->lease
->hostname
;
266 int sd_dhcp_client_prefixlen(const struct in_addr
*addr
) {
270 assert_return(addr
, -EADDRNOTAVAIL
);
272 mask
= be32toh(addr
->s_addr
);
281 int sd_dhcp_client_get_router(sd_dhcp_client
*client
, struct in_addr
*addr
) {
282 assert_return(client
, -EINVAL
);
283 assert_return(addr
, -EINVAL
);
285 switch (client
->state
) {
286 case DHCP_STATE_INIT
:
287 case DHCP_STATE_SELECTING
:
288 case DHCP_STATE_INIT_REBOOT
:
289 case DHCP_STATE_REBOOTING
:
290 case DHCP_STATE_REQUESTING
:
291 return -EADDRNOTAVAIL
;
293 case DHCP_STATE_BOUND
:
294 case DHCP_STATE_RENEWING
:
295 case DHCP_STATE_REBINDING
:
296 addr
->s_addr
= client
->lease
->router
;
304 int sd_dhcp_client_get_netmask(sd_dhcp_client
*client
, struct in_addr
*addr
) {
305 assert_return(client
, -EINVAL
);
306 assert_return(addr
, -EINVAL
);
308 switch (client
->state
) {
309 case DHCP_STATE_INIT
:
310 case DHCP_STATE_SELECTING
:
311 case DHCP_STATE_INIT_REBOOT
:
312 case DHCP_STATE_REBOOTING
:
313 case DHCP_STATE_REQUESTING
:
314 return -EADDRNOTAVAIL
;
316 case DHCP_STATE_BOUND
:
317 case DHCP_STATE_RENEWING
:
318 case DHCP_STATE_REBINDING
:
319 addr
->s_addr
= client
->lease
->subnet_mask
;
327 static int client_notify(sd_dhcp_client
*client
, int event
) {
329 client
->cb(client
, event
, client
->userdata
);
334 static void lease_free(DHCPLease
*lease
) {
338 free(lease
->hostname
);
343 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease
*, lease_free
);
344 #define _cleanup_lease_free_ _cleanup_(lease_freep)
346 static int client_stop(sd_dhcp_client
*client
, int error
) {
347 assert_return(client
, -EINVAL
);
349 client
->receive_message
=
350 sd_event_source_unref(client
->receive_message
);
356 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
358 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
359 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
360 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
364 client_notify(client
, error
);
366 switch (client
->state
) {
368 case DHCP_STATE_INIT
:
369 case DHCP_STATE_SELECTING
:
370 case DHCP_STATE_REQUESTING
:
371 case DHCP_STATE_BOUND
:
373 client
->start_time
= 0;
374 client
->state
= DHCP_STATE_INIT
;
377 case DHCP_STATE_INIT_REBOOT
:
378 case DHCP_STATE_REBOOTING
:
379 case DHCP_STATE_RENEWING
:
380 case DHCP_STATE_REBINDING
:
386 lease_free(client
->lease
);
387 client
->lease
= NULL
;
393 static int client_packet_init(sd_dhcp_client
*client
, uint8_t type
,
394 DHCPMessage
*message
, uint16_t secs
,
395 uint8_t **opt
, size_t *optlen
) {
399 *opt
= (uint8_t *)(message
+ 1);
405 message
->op
= BOOTREQUEST
;
407 message
->hlen
= ETHER_ADDR_LEN
;
408 message
->xid
= htobe32(client
->xid
);
410 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
411 refuse to issue an DHCP lease if 'secs' is set to zero */
412 message
->secs
= htobe16(secs
);
414 if (client
->state
== DHCP_STATE_RENEWING
||
415 client
->state
== DHCP_STATE_REBINDING
)
416 message
->ciaddr
= client
->lease
->address
;
418 memcpy(&message
->chaddr
, &client
->mac_addr
, ETH_ALEN
);
426 err
= dhcp_option_append(opt
, optlen
, DHCP_OPTION_MESSAGE_TYPE
, 1,
431 /* Some DHCP servers will refuse to issue an DHCP lease if the Cliient
432 Identifier option is not set */
433 err
= dhcp_option_append(opt
, optlen
, DHCP_OPTION_CLIENT_IDENTIFIER
,
434 ETH_ALEN
, &client
->mac_addr
);
438 if (type
== DHCP_DISCOVER
|| type
== DHCP_REQUEST
) {
439 err
= dhcp_option_append(opt
, optlen
,
440 DHCP_OPTION_PARAMETER_REQUEST_LIST
,
441 client
->req_opts_size
,
446 /* Some DHCP servers will send bigger DHCP packets than the
447 defined default size unless the Maximum Messge Size option
448 is explicitely set */
449 max_size
= htobe16(DHCP_IP_UDP_SIZE
+ DHCP_MESSAGE_SIZE
+
450 DHCP_CLIENT_MIN_OPTIONS_SIZE
);
451 err
= dhcp_option_append(opt
, optlen
,
452 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
,
461 static uint16_t client_checksum(void *buf
, int len
) {
470 for (i
= 0; i
< len
/ 2 ; i
++)
479 sum
= (sum
& 0xffff) + (sum
>> 16);
484 static void client_append_ip_headers(DHCPPacket
*packet
, uint16_t len
) {
485 packet
->ip
.version
= IPVERSION
;
486 packet
->ip
.ihl
= DHCP_IP_SIZE
/ 4;
487 packet
->ip
.tot_len
= htobe16(len
);
489 packet
->ip
.protocol
= IPPROTO_UDP
;
490 packet
->ip
.saddr
= INADDR_ANY
;
491 packet
->ip
.daddr
= INADDR_BROADCAST
;
493 packet
->udp
.source
= htobe16(DHCP_PORT_CLIENT
);
494 packet
->udp
.dest
= htobe16(DHCP_PORT_SERVER
);
495 packet
->udp
.len
= htobe16(len
- DHCP_IP_SIZE
);
497 packet
->ip
.check
= packet
->udp
.len
;
498 packet
->udp
.check
= client_checksum(&packet
->ip
.ttl
, len
- 8);
500 packet
->ip
.ttl
= IPDEFTTL
;
501 packet
->ip
.check
= 0;
502 packet
->ip
.check
= client_checksum(&packet
->ip
, DHCP_IP_SIZE
);
505 static int client_send_discover(sd_dhcp_client
*client
, uint16_t secs
) {
507 _cleanup_free_ DHCPPacket
*discover
;
511 optlen
= DHCP_CLIENT_MIN_OPTIONS_SIZE
;
512 len
= sizeof(DHCPPacket
) + optlen
;
514 discover
= malloc0(len
);
519 err
= client_packet_init(client
, DHCP_DISCOVER
, &discover
->dhcp
,
520 secs
, &opt
, &optlen
);
524 if (client
->last_addr
!= INADDR_ANY
) {
525 err
= dhcp_option_append(&opt
, &optlen
,
526 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
527 4, &client
->last_addr
);
532 err
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
536 client_append_ip_headers(discover
, len
);
538 err
= dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
544 static int client_send_request(sd_dhcp_client
*client
, uint16_t secs
) {
545 _cleanup_free_ DHCPPacket
*request
;
550 optlen
= DHCP_CLIENT_MIN_OPTIONS_SIZE
;
551 len
= DHCP_MESSAGE_SIZE
+ optlen
;
553 request
= malloc0(len
);
557 err
= client_packet_init(client
, DHCP_REQUEST
, &request
->dhcp
, secs
,
562 if (client
->state
== DHCP_STATE_REQUESTING
) {
563 err
= dhcp_option_append(&opt
, &optlen
,
564 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
565 4, &client
->lease
->address
);
569 err
= dhcp_option_append(&opt
, &optlen
,
570 DHCP_OPTION_SERVER_IDENTIFIER
,
571 4, &client
->lease
->server_address
);
576 err
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
580 if (client
->state
== DHCP_STATE_RENEWING
) {
581 err
= dhcp_network_send_udp_socket(client
->fd
,
582 client
->lease
->server_address
,
584 len
- DHCP_IP_UDP_SIZE
);
586 client_append_ip_headers(request
, len
);
588 err
= dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
595 static int client_timeout_resend(sd_event_source
*s
, uint64_t usec
,
597 sd_dhcp_client
*client
= userdata
;
598 usec_t next_timeout
= 0;
603 switch (client
->state
) {
604 case DHCP_STATE_RENEWING
:
606 time_left
= (client
->lease
->t2
- client
->lease
->t1
)/2;
610 next_timeout
= usec
+ time_left
* USEC_PER_SEC
;
614 case DHCP_STATE_REBINDING
:
616 time_left
= (client
->lease
->lifetime
- client
->lease
->t2
)/2;
620 next_timeout
= usec
+ time_left
* USEC_PER_SEC
;
623 case DHCP_STATE_INIT
:
624 case DHCP_STATE_INIT_REBOOT
:
625 case DHCP_STATE_REBOOTING
:
626 case DHCP_STATE_SELECTING
:
627 case DHCP_STATE_REQUESTING
:
628 case DHCP_STATE_BOUND
:
630 if (client
->attempt
< 64)
631 client
->attempt
*= 2;
633 next_timeout
= usec
+ (client
->attempt
- 1) * USEC_PER_SEC
;
638 next_timeout
+= (random_u32() & 0x1fffff);
640 err
= sd_event_add_monotonic(client
->event
, next_timeout
,
642 client_timeout_resend
, client
,
643 &client
->timeout_resend
);
647 secs
= (usec
- client
->start_time
) / USEC_PER_SEC
;
649 switch (client
->state
) {
650 case DHCP_STATE_INIT
:
651 err
= client_send_discover(client
, secs
);
653 client
->state
= DHCP_STATE_SELECTING
;
656 if (client
->attempt
>= 64)
662 case DHCP_STATE_SELECTING
:
663 err
= client_send_discover(client
, secs
);
664 if (err
< 0 && client
->attempt
>= 64)
669 case DHCP_STATE_REQUESTING
:
670 case DHCP_STATE_RENEWING
:
671 case DHCP_STATE_REBINDING
:
672 err
= client_send_request(client
, secs
);
673 if (err
< 0 && client
->attempt
>= 64)
676 client
->request_sent
= usec
;
680 case DHCP_STATE_INIT_REBOOT
:
681 case DHCP_STATE_REBOOTING
:
682 case DHCP_STATE_BOUND
:
690 client_stop(client
, err
);
692 /* Errors were dealt with when stopping the client, don't spill
693 errors into the event loop handler */
697 static int client_initialize_events(sd_dhcp_client
*client
, usec_t usec
) {
700 r
= sd_event_add_io(client
->event
, client
->fd
, EPOLLIN
,
701 client_receive_message
, client
,
702 &client
->receive_message
);
706 r
= sd_event_add_monotonic(client
->event
, usec
, 0,
707 client_timeout_resend
, client
,
708 &client
->timeout_resend
);
712 client_stop(client
, r
);
718 static int client_timeout_expire(sd_event_source
*s
, uint64_t usec
,
720 sd_dhcp_client
*client
= userdata
;
722 client_stop(client
, DHCP_EVENT_EXPIRED
);
727 static int client_timeout_t2(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
728 sd_dhcp_client
*client
= userdata
;
731 if (client
->fd
>= 0) {
732 client
->receive_message
=
733 sd_event_source_unref(client
->receive_message
);
738 client
->state
= DHCP_STATE_REBINDING
;
741 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
);
743 client_stop(client
, r
);
749 return client_initialize_events(client
, usec
);
752 static int client_timeout_t1(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
753 sd_dhcp_client
*client
= userdata
;
756 client
->state
= DHCP_STATE_RENEWING
;
759 r
= dhcp_network_bind_udp_socket(client
->index
,
760 client
->lease
->address
);
762 client_stop(client
, r
);
768 return client_initialize_events(client
, usec
);
771 static int client_parse_offer(uint8_t code
, uint8_t len
, const uint8_t *option
,
773 DHCPLease
*lease
= user_data
;
778 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
780 memcpy(&val
, option
, 4);
781 lease
->lifetime
= be32toh(val
);
786 case DHCP_OPTION_SERVER_IDENTIFIER
:
788 memcpy(&lease
->server_address
, option
, 4);
792 case DHCP_OPTION_SUBNET_MASK
:
794 memcpy(&lease
->subnet_mask
, option
, 4);
798 case DHCP_OPTION_ROUTER
:
800 memcpy(&lease
->router
, option
, 4);
804 case DHCP_OPTION_DOMAIN_NAME_SERVER
:
808 lease
->dns_size
= len
/ 4;
811 lease
->dns
= new0(struct in_addr
, lease
->dns_size
);
815 for (i
= 0; i
< lease
->dns_size
; i
++) {
816 memcpy(&lease
->dns
[i
].s_addr
, option
+ 4 * i
, 4);
822 case DHCP_OPTION_INTERFACE_MTU
:
826 memcpy(&mtu
, option
, 2);
827 lease
->mtu
= be16toh(mtu
);
835 case DHCP_OPTION_HOST_NAME
:
837 free(lease
->hostname
);
838 lease
->hostname
= strndup((const char *)option
, len
);
843 case DHCP_OPTION_RENEWAL_T1_TIME
:
845 memcpy(&val
, option
, 4);
846 lease
->t1
= be32toh(val
);
851 case DHCP_OPTION_REBINDING_T2_TIME
:
853 memcpy(&val
, option
, 4);
854 lease
->t2
= be32toh(val
);
863 static int client_verify_headers(sd_dhcp_client
*client
, DHCPPacket
*message
,
867 if (len
< (DHCP_IP_UDP_SIZE
+ DHCP_MESSAGE_SIZE
))
870 hdrlen
= message
->ip
.ihl
* 4;
871 if (hdrlen
< 20 || hdrlen
> len
|| client_checksum(&message
->ip
,
875 message
->ip
.check
= message
->udp
.len
;
878 if (hdrlen
+ be16toh(message
->udp
.len
) > len
||
879 client_checksum(&message
->ip
.ttl
, be16toh(message
->udp
.len
) + 12))
882 if (be16toh(message
->udp
.source
) != DHCP_PORT_SERVER
||
883 be16toh(message
->udp
.dest
) != DHCP_PORT_CLIENT
)
886 if (message
->dhcp
.op
!= BOOTREPLY
)
889 if (be32toh(message
->dhcp
.xid
) != client
->xid
)
892 if (memcmp(&message
->dhcp
.chaddr
[0], &client
->mac_addr
.ether_addr_octet
,
899 static int client_receive_offer(sd_dhcp_client
*client
, DHCPPacket
*offer
,
901 _cleanup_lease_free_ DHCPLease
*lease
= NULL
;
904 r
= client_verify_headers(client
, offer
, len
);
908 lease
= new0(DHCPLease
, 1);
912 len
= len
- DHCP_IP_UDP_SIZE
;
913 r
= dhcp_option_parse(&offer
->dhcp
, len
, client_parse_offer
,
918 lease
->address
= offer
->dhcp
.yiaddr
;
920 if (lease
->address
== INADDR_ANY
||
921 lease
->server_address
== INADDR_ANY
||
922 lease
->subnet_mask
== INADDR_ANY
||
923 lease
->lifetime
== 0)
926 client
->lease
= lease
;
932 static int client_receive_ack(sd_dhcp_client
*client
, const uint8_t *buf
,
936 _cleanup_lease_free_ DHCPLease
*lease
= NULL
;
939 if (client
->state
== DHCP_STATE_RENEWING
) {
940 dhcp
= (DHCPMessage
*)buf
;
942 ack
= (DHCPPacket
*)buf
;
944 r
= client_verify_headers(client
, ack
, len
);
949 len
-= DHCP_IP_UDP_SIZE
;
952 lease
= new0(DHCPLease
, 1);
956 r
= dhcp_option_parse(dhcp
, len
, client_parse_offer
, lease
);
958 return DHCP_EVENT_NO_LEASE
;
963 lease
->address
= dhcp
->yiaddr
;
965 if (lease
->address
== INADDR_ANY
||
966 lease
->server_address
== INADDR_ANY
||
967 lease
->subnet_mask
== INADDR_ANY
|| lease
->lifetime
== 0)
970 r
= DHCP_EVENT_IP_ACQUIRE
;
972 if (client
->lease
->address
!= lease
->address
||
973 client
->lease
->subnet_mask
!= lease
->subnet_mask
||
974 client
->lease
->router
!= lease
->router
) {
975 r
= DHCP_EVENT_IP_CHANGE
;
978 lease_free(client
->lease
);
981 client
->lease
= lease
;
987 static uint64_t client_compute_timeout(uint64_t request_sent
,
989 return request_sent
+ (lifetime
- 3) * USEC_PER_SEC
+
990 + (random_u32() & 0x1fffff);
993 static int client_set_lease_timeouts(sd_dhcp_client
*client
, uint64_t usec
) {
994 uint64_t next_timeout
;
997 if (client
->lease
->lifetime
< 10)
1000 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
1001 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
1002 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
1004 if (!client
->lease
->t1
)
1005 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
1007 next_timeout
= client_compute_timeout(client
->request_sent
,
1009 if (next_timeout
< usec
)
1012 r
= sd_event_add_monotonic(client
->event
, next_timeout
,
1014 client_timeout_t1
, client
,
1015 &client
->timeout_t1
);
1019 if (!client
->lease
->t2
)
1020 client
->lease
->t2
= client
->lease
->lifetime
* 7 / 8;
1022 if (client
->lease
->t2
< client
->lease
->t1
)
1025 if (client
->lease
->lifetime
< client
->lease
->t2
)
1028 next_timeout
= client_compute_timeout(client
->request_sent
,
1030 if (next_timeout
< usec
)
1033 r
= sd_event_add_monotonic(client
->event
, next_timeout
,
1035 client_timeout_t2
, client
,
1036 &client
->timeout_t2
);
1040 next_timeout
= client_compute_timeout(client
->request_sent
,
1041 client
->lease
->lifetime
);
1042 if (next_timeout
< usec
)
1045 r
= sd_event_add_monotonic(client
->event
, next_timeout
,
1047 client_timeout_expire
, client
,
1048 &client
->timeout_expire
);
1055 static int client_receive_message(sd_event_source
*s
, int fd
,
1056 uint32_t revents
, void *userdata
) {
1057 sd_dhcp_client
*client
= userdata
;
1058 uint8_t buf
[sizeof(DHCPPacket
) + DHCP_CLIENT_MIN_OPTIONS_SIZE
];
1059 int buflen
= sizeof(buf
);
1060 int len
, r
= 0, notify_event
= 0;
1061 DHCPPacket
*message
;
1064 len
= read(fd
, &buf
, buflen
);
1068 r
= sd_event_get_now_monotonic(client
->event
, &time_now
);
1072 switch (client
->state
) {
1073 case DHCP_STATE_SELECTING
:
1075 message
= (DHCPPacket
*)&buf
;
1077 if (client_receive_offer(client
, message
, len
) >= 0) {
1079 client
->timeout_resend
=
1080 sd_event_source_unref(client
->timeout_resend
);
1082 client
->state
= DHCP_STATE_REQUESTING
;
1083 client
->attempt
= 1;
1085 r
= sd_event_add_monotonic(client
->event
, time_now
, 0,
1086 client_timeout_resend
,
1088 &client
->timeout_resend
);
1095 case DHCP_STATE_REQUESTING
:
1096 case DHCP_STATE_RENEWING
:
1097 case DHCP_STATE_REBINDING
:
1099 r
= client_receive_ack(client
, buf
, len
);
1101 if (r
== DHCP_EVENT_NO_LEASE
)
1105 client
->timeout_resend
=
1106 sd_event_source_unref(client
->timeout_resend
);
1108 if (client
->state
== DHCP_STATE_REQUESTING
)
1109 notify_event
= DHCP_EVENT_IP_ACQUIRE
;
1110 else if (r
!= DHCP_EVENT_IP_ACQUIRE
)
1113 client
->state
= DHCP_STATE_BOUND
;
1114 client
->attempt
= 1;
1116 client
->last_addr
= client
->lease
->address
;
1118 r
= client_set_lease_timeouts(client
, time_now
);
1123 client_notify(client
, notify_event
);
1125 client
->receive_message
=
1126 sd_event_source_unref(client
->receive_message
);
1135 case DHCP_STATE_INIT
:
1136 case DHCP_STATE_INIT_REBOOT
:
1137 case DHCP_STATE_REBOOTING
:
1138 case DHCP_STATE_BOUND
:
1144 if (r
< 0 || r
== DHCP_EVENT_NO_LEASE
)
1145 return client_stop(client
, r
);
1150 int sd_dhcp_client_start(sd_dhcp_client
*client
) {
1153 assert_return(client
, -EINVAL
);
1154 assert_return(client
->index
> 0, -EINVAL
);
1155 assert_return(client
->state
== DHCP_STATE_INIT
||
1156 client
->state
== DHCP_STATE_INIT_REBOOT
, -EBUSY
);
1158 client
->xid
= random_u32();
1160 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
);
1163 client_stop(client
, r
);
1168 client
->start_time
= now(CLOCK_MONOTONIC
);
1170 return client_initialize_events(client
, client
->start_time
);
1173 int sd_dhcp_client_stop(sd_dhcp_client
*client
) {
1174 return client_stop(client
, DHCP_EVENT_STOP
);
1177 sd_dhcp_client
*sd_dhcp_client_free(sd_dhcp_client
*client
) {
1178 assert_return(client
, NULL
);
1180 sd_dhcp_client_stop(client
);
1182 sd_event_unref(client
->event
);
1183 free(client
->req_opts
);
1189 sd_dhcp_client
*sd_dhcp_client_new(sd_event
*event
) {
1190 sd_dhcp_client
*client
;
1192 assert_return(event
, NULL
);
1194 client
= new0(sd_dhcp_client
, 1);
1198 client
->event
= sd_event_ref(event
);
1199 client
->state
= DHCP_STATE_INIT
;
1202 client
->attempt
= 1;
1204 client
->req_opts_size
= ELEMENTSOF(default_req_opts
);
1206 client
->req_opts
= memdup(default_req_opts
, client
->req_opts_size
);
1207 if (!client
->req_opts
) {