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
;
51 typedef struct DHCPLease DHCPLease
;
53 struct sd_dhcp_client
{
57 sd_event_source
*timeout_resend
;
60 union sockaddr_union link
;
61 sd_event_source
*receive_message
;
63 size_t req_opts_allocated
;
66 struct ether_addr mac_addr
;
71 sd_event_source
*timeout_t1
;
72 sd_event_source
*timeout_t2
;
73 sd_event_source
*timeout_expire
;
74 sd_dhcp_client_cb_t cb
;
79 static const uint8_t default_req_opts
[] = {
80 DHCP_OPTION_SUBNET_MASK
,
82 DHCP_OPTION_HOST_NAME
,
83 DHCP_OPTION_DOMAIN_NAME
,
84 DHCP_OPTION_DOMAIN_NAME_SERVER
,
85 DHCP_OPTION_NTP_SERVER
,
88 static int client_receive_message(sd_event_source
*s
, int fd
,
89 uint32_t revents
, void *userdata
);
91 int sd_dhcp_client_set_callback(sd_dhcp_client
*client
, sd_dhcp_client_cb_t cb
,
93 assert_return(client
, -EINVAL
);
96 client
->userdata
= userdata
;
101 int sd_dhcp_client_set_request_option(sd_dhcp_client
*client
, uint8_t option
) {
104 assert_return(client
, -EINVAL
);
105 assert_return (client
->state
== DHCP_STATE_INIT
, -EBUSY
);
108 case DHCP_OPTION_PAD
:
109 case DHCP_OPTION_OVERLOAD
:
110 case DHCP_OPTION_MESSAGE_TYPE
:
111 case DHCP_OPTION_PARAMETER_REQUEST_LIST
:
112 case DHCP_OPTION_END
:
119 for (i
= 0; i
< client
->req_opts_size
; i
++)
120 if (client
->req_opts
[i
] == option
)
123 if (!GREEDY_REALLOC(client
->req_opts
, client
->req_opts_allocated
,
124 client
->req_opts_size
+ 1))
127 client
->req_opts
[client
->req_opts_size
++] = option
;
132 int sd_dhcp_client_set_request_address(sd_dhcp_client
*client
,
133 const struct in_addr
*last_addr
) {
134 assert_return(client
, -EINVAL
);
135 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
138 client
->last_addr
= last_addr
->s_addr
;
140 client
->last_addr
= INADDR_ANY
;
145 int sd_dhcp_client_set_index(sd_dhcp_client
*client
, int interface_index
) {
146 assert_return(client
, -EINVAL
);
147 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
148 assert_return(interface_index
>= -1, -EINVAL
);
150 client
->index
= interface_index
;
155 int sd_dhcp_client_set_mac(sd_dhcp_client
*client
,
156 const struct ether_addr
*addr
) {
157 assert_return(client
, -EINVAL
);
158 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
160 memcpy(&client
->mac_addr
, addr
, ETH_ALEN
);
165 int sd_dhcp_client_get_address(sd_dhcp_client
*client
, struct in_addr
*addr
) {
166 assert_return(client
, -EINVAL
);
167 assert_return(addr
, -EINVAL
);
169 switch (client
->state
) {
170 case DHCP_STATE_INIT
:
171 case DHCP_STATE_SELECTING
:
172 case DHCP_STATE_INIT_REBOOT
:
173 case DHCP_STATE_REBOOTING
:
174 case DHCP_STATE_REQUESTING
:
175 return -EADDRNOTAVAIL
;
177 case DHCP_STATE_BOUND
:
178 case DHCP_STATE_RENEWING
:
179 case DHCP_STATE_REBINDING
:
180 addr
->s_addr
= client
->lease
->address
;
188 int sd_dhcp_client_get_mtu(sd_dhcp_client
*client
, uint16_t *mtu
) {
189 assert_return(client
, -EINVAL
);
190 assert_return(mtu
, -EINVAL
);
192 switch (client
->state
) {
193 case DHCP_STATE_INIT
:
194 case DHCP_STATE_SELECTING
:
195 case DHCP_STATE_INIT_REBOOT
:
196 case DHCP_STATE_REBOOTING
:
197 case DHCP_STATE_REQUESTING
:
198 return -EADDRNOTAVAIL
;
200 case DHCP_STATE_BOUND
:
201 case DHCP_STATE_RENEWING
:
202 case DHCP_STATE_REBINDING
:
203 if (client
->lease
->mtu
)
204 *mtu
= client
->lease
->mtu
;
214 int sd_dhcp_client_get_dns(sd_dhcp_client
*client
, struct in_addr
**addr
, size_t *addr_size
) {
215 assert_return(client
, -EINVAL
);
216 assert_return(addr
, -EINVAL
);
217 assert_return(addr_size
, -EINVAL
);
219 switch (client
->state
) {
220 case DHCP_STATE_INIT
:
221 case DHCP_STATE_SELECTING
:
222 case DHCP_STATE_INIT_REBOOT
:
223 case DHCP_STATE_REBOOTING
:
224 case DHCP_STATE_REQUESTING
:
225 return -EADDRNOTAVAIL
;
227 case DHCP_STATE_BOUND
:
228 case DHCP_STATE_RENEWING
:
229 case DHCP_STATE_REBINDING
:
230 if (client
->lease
->dns_size
) {
231 *addr_size
= client
->lease
->dns_size
;
232 *addr
= client
->lease
->dns
;
242 int sd_dhcp_client_get_domainname(sd_dhcp_client
*client
, const char **domainname
) {
243 assert_return(client
, -EINVAL
);
244 assert_return(domainname
, -EINVAL
);
246 switch (client
->state
) {
247 case DHCP_STATE_INIT
:
248 case DHCP_STATE_SELECTING
:
249 case DHCP_STATE_INIT_REBOOT
:
250 case DHCP_STATE_REBOOTING
:
251 case DHCP_STATE_REQUESTING
:
252 return -EADDRNOTAVAIL
;
254 case DHCP_STATE_BOUND
:
255 case DHCP_STATE_RENEWING
:
256 case DHCP_STATE_REBINDING
:
257 if (client
->lease
->domainname
)
258 *domainname
= client
->lease
->domainname
;
268 int sd_dhcp_client_get_hostname(sd_dhcp_client
*client
, const char **hostname
) {
269 assert_return(client
, -EINVAL
);
270 assert_return(hostname
, -EINVAL
);
272 switch (client
->state
) {
273 case DHCP_STATE_INIT
:
274 case DHCP_STATE_SELECTING
:
275 case DHCP_STATE_INIT_REBOOT
:
276 case DHCP_STATE_REBOOTING
:
277 case DHCP_STATE_REQUESTING
:
278 return -EADDRNOTAVAIL
;
280 case DHCP_STATE_BOUND
:
281 case DHCP_STATE_RENEWING
:
282 case DHCP_STATE_REBINDING
:
283 if (client
->lease
->hostname
)
284 *hostname
= client
->lease
->hostname
;
294 int sd_dhcp_client_prefixlen(const struct in_addr
*addr
) {
298 assert_return(addr
, -EADDRNOTAVAIL
);
300 mask
= be32toh(addr
->s_addr
);
309 int sd_dhcp_client_get_router(sd_dhcp_client
*client
, struct in_addr
*addr
) {
310 assert_return(client
, -EINVAL
);
311 assert_return(addr
, -EINVAL
);
313 switch (client
->state
) {
314 case DHCP_STATE_INIT
:
315 case DHCP_STATE_SELECTING
:
316 case DHCP_STATE_INIT_REBOOT
:
317 case DHCP_STATE_REBOOTING
:
318 case DHCP_STATE_REQUESTING
:
319 return -EADDRNOTAVAIL
;
321 case DHCP_STATE_BOUND
:
322 case DHCP_STATE_RENEWING
:
323 case DHCP_STATE_REBINDING
:
324 addr
->s_addr
= client
->lease
->router
;
332 int sd_dhcp_client_get_netmask(sd_dhcp_client
*client
, struct in_addr
*addr
) {
333 assert_return(client
, -EINVAL
);
334 assert_return(addr
, -EINVAL
);
336 switch (client
->state
) {
337 case DHCP_STATE_INIT
:
338 case DHCP_STATE_SELECTING
:
339 case DHCP_STATE_INIT_REBOOT
:
340 case DHCP_STATE_REBOOTING
:
341 case DHCP_STATE_REQUESTING
:
342 return -EADDRNOTAVAIL
;
344 case DHCP_STATE_BOUND
:
345 case DHCP_STATE_RENEWING
:
346 case DHCP_STATE_REBINDING
:
347 addr
->s_addr
= client
->lease
->subnet_mask
;
355 static int client_notify(sd_dhcp_client
*client
, int event
) {
357 client
->cb(client
, event
, client
->userdata
);
362 static void lease_free(DHCPLease
*lease
) {
366 free(lease
->hostname
);
367 free(lease
->domainname
);
372 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease
*, lease_free
);
373 #define _cleanup_lease_free_ _cleanup_(lease_freep)
375 static int client_stop(sd_dhcp_client
*client
, int error
) {
376 assert_return(client
, -EINVAL
);
378 client
->receive_message
=
379 sd_event_source_unref(client
->receive_message
);
385 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
387 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
388 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
389 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
393 client_notify(client
, error
);
395 switch (client
->state
) {
397 case DHCP_STATE_INIT
:
398 case DHCP_STATE_SELECTING
:
399 case DHCP_STATE_REQUESTING
:
400 case DHCP_STATE_BOUND
:
402 client
->start_time
= 0;
403 client
->state
= DHCP_STATE_INIT
;
406 case DHCP_STATE_INIT_REBOOT
:
407 case DHCP_STATE_REBOOTING
:
408 case DHCP_STATE_RENEWING
:
409 case DHCP_STATE_REBINDING
:
415 lease_free(client
->lease
);
416 client
->lease
= NULL
;
422 static int client_packet_init(sd_dhcp_client
*client
, uint8_t type
,
423 DHCPMessage
*message
, uint16_t secs
,
424 uint8_t **opt
, size_t *optlen
) {
428 *opt
= (uint8_t *)(message
+ 1);
434 message
->op
= BOOTREQUEST
;
436 message
->hlen
= ETHER_ADDR_LEN
;
437 message
->xid
= htobe32(client
->xid
);
439 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
440 refuse to issue an DHCP lease if 'secs' is set to zero */
441 message
->secs
= htobe16(secs
);
443 if (client
->state
== DHCP_STATE_RENEWING
||
444 client
->state
== DHCP_STATE_REBINDING
)
445 message
->ciaddr
= client
->lease
->address
;
447 memcpy(&message
->chaddr
, &client
->mac_addr
, ETH_ALEN
);
455 err
= dhcp_option_append(opt
, optlen
, DHCP_OPTION_MESSAGE_TYPE
, 1,
460 /* Some DHCP servers will refuse to issue an DHCP lease if the Cliient
461 Identifier option is not set */
462 err
= dhcp_option_append(opt
, optlen
, DHCP_OPTION_CLIENT_IDENTIFIER
,
463 ETH_ALEN
, &client
->mac_addr
);
467 if (type
== DHCP_DISCOVER
|| type
== DHCP_REQUEST
) {
468 err
= dhcp_option_append(opt
, optlen
,
469 DHCP_OPTION_PARAMETER_REQUEST_LIST
,
470 client
->req_opts_size
,
475 /* Some DHCP servers will send bigger DHCP packets than the
476 defined default size unless the Maximum Messge Size option
477 is explicitely set */
478 max_size
= htobe16(DHCP_IP_UDP_SIZE
+ DHCP_MESSAGE_SIZE
+
479 DHCP_CLIENT_MIN_OPTIONS_SIZE
);
480 err
= dhcp_option_append(opt
, optlen
,
481 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
,
490 static uint16_t client_checksum(void *buf
, int len
) {
499 for (i
= 0; i
< len
/ 2 ; i
++)
508 sum
= (sum
& 0xffff) + (sum
>> 16);
513 static void client_append_ip_headers(DHCPPacket
*packet
, uint16_t len
) {
514 packet
->ip
.version
= IPVERSION
;
515 packet
->ip
.ihl
= DHCP_IP_SIZE
/ 4;
516 packet
->ip
.tot_len
= htobe16(len
);
518 packet
->ip
.protocol
= IPPROTO_UDP
;
519 packet
->ip
.saddr
= INADDR_ANY
;
520 packet
->ip
.daddr
= INADDR_BROADCAST
;
522 packet
->udp
.source
= htobe16(DHCP_PORT_CLIENT
);
523 packet
->udp
.dest
= htobe16(DHCP_PORT_SERVER
);
524 packet
->udp
.len
= htobe16(len
- DHCP_IP_SIZE
);
526 packet
->ip
.check
= packet
->udp
.len
;
527 packet
->udp
.check
= client_checksum(&packet
->ip
.ttl
, len
- 8);
529 packet
->ip
.ttl
= IPDEFTTL
;
530 packet
->ip
.check
= 0;
531 packet
->ip
.check
= client_checksum(&packet
->ip
, DHCP_IP_SIZE
);
534 static int client_send_discover(sd_dhcp_client
*client
, uint16_t secs
) {
536 _cleanup_free_ DHCPPacket
*discover
;
540 optlen
= DHCP_CLIENT_MIN_OPTIONS_SIZE
;
541 len
= sizeof(DHCPPacket
) + optlen
;
543 discover
= malloc0(len
);
548 err
= client_packet_init(client
, DHCP_DISCOVER
, &discover
->dhcp
,
549 secs
, &opt
, &optlen
);
553 if (client
->last_addr
!= INADDR_ANY
) {
554 err
= dhcp_option_append(&opt
, &optlen
,
555 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
556 4, &client
->last_addr
);
561 err
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
565 client_append_ip_headers(discover
, len
);
567 err
= dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
573 static int client_send_request(sd_dhcp_client
*client
, uint16_t secs
) {
574 _cleanup_free_ DHCPPacket
*request
;
579 optlen
= DHCP_CLIENT_MIN_OPTIONS_SIZE
;
580 len
= DHCP_MESSAGE_SIZE
+ optlen
;
582 request
= malloc0(len
);
586 err
= client_packet_init(client
, DHCP_REQUEST
, &request
->dhcp
, secs
,
591 if (client
->state
== DHCP_STATE_REQUESTING
) {
592 err
= dhcp_option_append(&opt
, &optlen
,
593 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
594 4, &client
->lease
->address
);
598 err
= dhcp_option_append(&opt
, &optlen
,
599 DHCP_OPTION_SERVER_IDENTIFIER
,
600 4, &client
->lease
->server_address
);
605 err
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
609 if (client
->state
== DHCP_STATE_RENEWING
) {
610 err
= dhcp_network_send_udp_socket(client
->fd
,
611 client
->lease
->server_address
,
613 len
- DHCP_IP_UDP_SIZE
);
615 client_append_ip_headers(request
, len
);
617 err
= dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
624 static int client_timeout_resend(sd_event_source
*s
, uint64_t usec
,
626 sd_dhcp_client
*client
= userdata
;
627 usec_t next_timeout
= 0;
634 assert(client
->event
);
636 switch (client
->state
) {
637 case DHCP_STATE_RENEWING
:
639 time_left
= (client
->lease
->t2
- client
->lease
->t1
)/2;
643 next_timeout
= usec
+ time_left
* USEC_PER_SEC
;
647 case DHCP_STATE_REBINDING
:
649 time_left
= (client
->lease
->lifetime
- client
->lease
->t2
)/2;
653 next_timeout
= usec
+ time_left
* USEC_PER_SEC
;
656 case DHCP_STATE_INIT
:
657 case DHCP_STATE_INIT_REBOOT
:
658 case DHCP_STATE_REBOOTING
:
659 case DHCP_STATE_SELECTING
:
660 case DHCP_STATE_REQUESTING
:
661 case DHCP_STATE_BOUND
:
663 if (client
->attempt
< 64)
664 client
->attempt
*= 2;
666 next_timeout
= usec
+ (client
->attempt
- 1) * USEC_PER_SEC
;
671 next_timeout
+= (random_u32() & 0x1fffff);
673 r
= sd_event_add_monotonic(client
->event
, next_timeout
,
675 client_timeout_resend
, client
,
676 &client
->timeout_resend
);
680 r
= sd_event_source_set_priority(client
->timeout_resend
, client
->event_priority
);
684 secs
= (usec
- client
->start_time
) / USEC_PER_SEC
;
686 switch (client
->state
) {
687 case DHCP_STATE_INIT
:
688 r
= client_send_discover(client
, secs
);
690 client
->state
= DHCP_STATE_SELECTING
;
693 if (client
->attempt
>= 64)
699 case DHCP_STATE_SELECTING
:
700 r
= client_send_discover(client
, secs
);
701 if (r
< 0 && client
->attempt
>= 64)
706 case DHCP_STATE_REQUESTING
:
707 case DHCP_STATE_RENEWING
:
708 case DHCP_STATE_REBINDING
:
709 r
= client_send_request(client
, secs
);
710 if (r
< 0 && client
->attempt
>= 64)
713 client
->request_sent
= usec
;
717 case DHCP_STATE_INIT_REBOOT
:
718 case DHCP_STATE_REBOOTING
:
719 case DHCP_STATE_BOUND
:
727 client_stop(client
, r
);
729 /* Errors were dealt with when stopping the client, don't spill
730 errors into the event loop handler */
734 static int client_initialize_events(sd_dhcp_client
*client
, usec_t usec
) {
738 assert(client
->event
);
740 r
= sd_event_add_io(client
->event
, client
->fd
, EPOLLIN
,
741 client_receive_message
, client
,
742 &client
->receive_message
);
746 r
= sd_event_source_set_priority(client
->receive_message
, client
->event_priority
);
750 r
= sd_event_add_monotonic(client
->event
, usec
, 0,
751 client_timeout_resend
, client
,
752 &client
->timeout_resend
);
756 r
= sd_event_source_set_priority(client
->timeout_resend
, client
->event_priority
);
760 client_stop(client
, r
);
766 static int client_timeout_expire(sd_event_source
*s
, uint64_t usec
,
768 sd_dhcp_client
*client
= userdata
;
770 client_stop(client
, DHCP_EVENT_EXPIRED
);
775 static int client_timeout_t2(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
776 sd_dhcp_client
*client
= userdata
;
779 if (client
->fd
>= 0) {
780 client
->receive_message
=
781 sd_event_source_unref(client
->receive_message
);
786 client
->state
= DHCP_STATE_REBINDING
;
789 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
);
791 client_stop(client
, r
);
797 return client_initialize_events(client
, usec
);
800 static int client_timeout_t1(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
801 sd_dhcp_client
*client
= userdata
;
804 client
->state
= DHCP_STATE_RENEWING
;
807 r
= dhcp_network_bind_udp_socket(client
->index
,
808 client
->lease
->address
);
810 client_stop(client
, r
);
816 return client_initialize_events(client
, usec
);
819 static int client_parse_offer(uint8_t code
, uint8_t len
, const uint8_t *option
,
821 DHCPLease
*lease
= user_data
;
826 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
828 memcpy(&val
, option
, 4);
829 lease
->lifetime
= be32toh(val
);
834 case DHCP_OPTION_SERVER_IDENTIFIER
:
836 memcpy(&lease
->server_address
, option
, 4);
840 case DHCP_OPTION_SUBNET_MASK
:
842 memcpy(&lease
->subnet_mask
, option
, 4);
846 case DHCP_OPTION_ROUTER
:
848 memcpy(&lease
->router
, option
, 4);
852 case DHCP_OPTION_DOMAIN_NAME_SERVER
:
856 lease
->dns_size
= len
/ 4;
859 lease
->dns
= new0(struct in_addr
, lease
->dns_size
);
863 for (i
= 0; i
< lease
->dns_size
; i
++) {
864 memcpy(&lease
->dns
[i
].s_addr
, option
+ 4 * i
, 4);
870 case DHCP_OPTION_INTERFACE_MTU
:
874 memcpy(&mtu
, option
, 2);
875 lease
->mtu
= be16toh(mtu
);
883 case DHCP_OPTION_DOMAIN_NAME
:
885 free(lease
->domainname
);
886 lease
->domainname
= strndup((const char *)option
, len
);
891 case DHCP_OPTION_HOST_NAME
:
893 free(lease
->hostname
);
894 lease
->hostname
= strndup((const char *)option
, len
);
899 case DHCP_OPTION_RENEWAL_T1_TIME
:
901 memcpy(&val
, option
, 4);
902 lease
->t1
= be32toh(val
);
907 case DHCP_OPTION_REBINDING_T2_TIME
:
909 memcpy(&val
, option
, 4);
910 lease
->t2
= be32toh(val
);
919 static int client_verify_headers(sd_dhcp_client
*client
, DHCPPacket
*message
,
923 if (len
< (DHCP_IP_UDP_SIZE
+ DHCP_MESSAGE_SIZE
))
926 hdrlen
= message
->ip
.ihl
* 4;
927 if (hdrlen
< 20 || hdrlen
> len
|| client_checksum(&message
->ip
,
931 message
->ip
.check
= message
->udp
.len
;
934 if (hdrlen
+ be16toh(message
->udp
.len
) > len
||
935 client_checksum(&message
->ip
.ttl
, be16toh(message
->udp
.len
) + 12))
938 if (be16toh(message
->udp
.source
) != DHCP_PORT_SERVER
||
939 be16toh(message
->udp
.dest
) != DHCP_PORT_CLIENT
)
942 if (message
->dhcp
.op
!= BOOTREPLY
)
945 if (be32toh(message
->dhcp
.xid
) != client
->xid
)
948 if (memcmp(&message
->dhcp
.chaddr
[0], &client
->mac_addr
.ether_addr_octet
,
955 static int client_receive_offer(sd_dhcp_client
*client
, DHCPPacket
*offer
,
957 _cleanup_lease_free_ DHCPLease
*lease
= NULL
;
960 r
= client_verify_headers(client
, offer
, len
);
964 lease
= new0(DHCPLease
, 1);
968 len
= len
- DHCP_IP_UDP_SIZE
;
969 r
= dhcp_option_parse(&offer
->dhcp
, len
, client_parse_offer
,
974 lease
->address
= offer
->dhcp
.yiaddr
;
976 if (lease
->address
== INADDR_ANY
||
977 lease
->server_address
== INADDR_ANY
||
978 lease
->subnet_mask
== INADDR_ANY
||
979 lease
->lifetime
== 0)
982 client
->lease
= lease
;
988 static int client_receive_ack(sd_dhcp_client
*client
, const uint8_t *buf
,
992 _cleanup_lease_free_ DHCPLease
*lease
= NULL
;
995 if (client
->state
== DHCP_STATE_RENEWING
) {
996 dhcp
= (DHCPMessage
*)buf
;
998 ack
= (DHCPPacket
*)buf
;
1000 r
= client_verify_headers(client
, ack
, len
);
1005 len
-= DHCP_IP_UDP_SIZE
;
1008 lease
= new0(DHCPLease
, 1);
1012 r
= dhcp_option_parse(dhcp
, len
, client_parse_offer
, lease
);
1014 return DHCP_EVENT_NO_LEASE
;
1019 lease
->address
= dhcp
->yiaddr
;
1021 if (lease
->address
== INADDR_ANY
||
1022 lease
->server_address
== INADDR_ANY
||
1023 lease
->subnet_mask
== INADDR_ANY
|| lease
->lifetime
== 0)
1026 r
= DHCP_EVENT_IP_ACQUIRE
;
1027 if (client
->lease
) {
1028 if (client
->lease
->address
!= lease
->address
||
1029 client
->lease
->subnet_mask
!= lease
->subnet_mask
||
1030 client
->lease
->router
!= lease
->router
) {
1031 r
= DHCP_EVENT_IP_CHANGE
;
1034 lease_free(client
->lease
);
1037 client
->lease
= lease
;
1043 static uint64_t client_compute_timeout(uint64_t request_sent
,
1044 uint32_t lifetime
) {
1045 return request_sent
+ (lifetime
- 3) * USEC_PER_SEC
+
1046 + (random_u32() & 0x1fffff);
1049 static int client_set_lease_timeouts(sd_dhcp_client
*client
, uint64_t usec
) {
1050 uint64_t next_timeout
;
1054 assert(client
->event
);
1056 if (client
->lease
->lifetime
< 10)
1059 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
1060 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
1061 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
1063 if (!client
->lease
->t1
)
1064 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
1066 next_timeout
= client_compute_timeout(client
->request_sent
,
1068 if (next_timeout
< usec
)
1071 r
= sd_event_add_monotonic(client
->event
, next_timeout
,
1073 client_timeout_t1
, client
,
1074 &client
->timeout_t1
);
1078 r
= sd_event_source_set_priority(client
->timeout_t1
, client
->event_priority
);
1082 if (!client
->lease
->t2
)
1083 client
->lease
->t2
= client
->lease
->lifetime
* 7 / 8;
1085 if (client
->lease
->t2
< client
->lease
->t1
)
1088 if (client
->lease
->lifetime
< client
->lease
->t2
)
1091 next_timeout
= client_compute_timeout(client
->request_sent
,
1093 if (next_timeout
< usec
)
1096 r
= sd_event_add_monotonic(client
->event
, next_timeout
,
1098 client_timeout_t2
, client
,
1099 &client
->timeout_t2
);
1103 r
= sd_event_source_set_priority(client
->timeout_t2
, client
->event_priority
);
1107 next_timeout
= client_compute_timeout(client
->request_sent
,
1108 client
->lease
->lifetime
);
1109 if (next_timeout
< usec
)
1112 r
= sd_event_add_monotonic(client
->event
, next_timeout
,
1114 client_timeout_expire
, client
,
1115 &client
->timeout_expire
);
1119 r
= sd_event_source_set_priority(client
->timeout_expire
, client
->event_priority
);
1126 static int client_receive_message(sd_event_source
*s
, int fd
,
1127 uint32_t revents
, void *userdata
) {
1128 sd_dhcp_client
*client
= userdata
;
1129 uint8_t buf
[sizeof(DHCPPacket
) + DHCP_CLIENT_MIN_OPTIONS_SIZE
];
1130 int buflen
= sizeof(buf
);
1131 int len
, r
= 0, notify_event
= 0;
1132 DHCPPacket
*message
;
1137 assert(client
->event
);
1139 len
= read(fd
, &buf
, buflen
);
1143 r
= sd_event_get_now_monotonic(client
->event
, &time_now
);
1147 switch (client
->state
) {
1148 case DHCP_STATE_SELECTING
:
1150 message
= (DHCPPacket
*)&buf
;
1152 if (client_receive_offer(client
, message
, len
) >= 0) {
1154 client
->timeout_resend
=
1155 sd_event_source_unref(client
->timeout_resend
);
1157 client
->state
= DHCP_STATE_REQUESTING
;
1158 client
->attempt
= 1;
1160 r
= sd_event_add_monotonic(client
->event
, time_now
, 0,
1161 client_timeout_resend
,
1163 &client
->timeout_resend
);
1167 r
= sd_event_source_set_priority(client
->timeout_resend
, client
->event_priority
);
1174 case DHCP_STATE_REQUESTING
:
1175 case DHCP_STATE_RENEWING
:
1176 case DHCP_STATE_REBINDING
:
1178 r
= client_receive_ack(client
, buf
, len
);
1180 if (r
== DHCP_EVENT_NO_LEASE
)
1184 client
->timeout_resend
=
1185 sd_event_source_unref(client
->timeout_resend
);
1187 if (client
->state
== DHCP_STATE_REQUESTING
)
1188 notify_event
= DHCP_EVENT_IP_ACQUIRE
;
1189 else if (r
!= DHCP_EVENT_IP_ACQUIRE
)
1192 client
->state
= DHCP_STATE_BOUND
;
1193 client
->attempt
= 1;
1195 client
->last_addr
= client
->lease
->address
;
1197 r
= client_set_lease_timeouts(client
, time_now
);
1202 client_notify(client
, notify_event
);
1204 client
->receive_message
=
1205 sd_event_source_unref(client
->receive_message
);
1214 case DHCP_STATE_INIT
:
1215 case DHCP_STATE_INIT_REBOOT
:
1216 case DHCP_STATE_REBOOTING
:
1217 case DHCP_STATE_BOUND
:
1223 if (r
< 0 || r
== DHCP_EVENT_NO_LEASE
)
1224 return client_stop(client
, r
);
1229 int sd_dhcp_client_start(sd_dhcp_client
*client
) {
1232 assert_return(client
, -EINVAL
);
1233 assert_return(client
->event
, -EINVAL
);
1234 assert_return(client
->index
> 0, -EINVAL
);
1235 assert_return(client
->state
== DHCP_STATE_INIT
||
1236 client
->state
== DHCP_STATE_INIT_REBOOT
, -EBUSY
);
1238 client
->xid
= random_u32();
1240 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
);
1243 client_stop(client
, r
);
1248 client
->start_time
= now(CLOCK_MONOTONIC
);
1250 return client_initialize_events(client
, client
->start_time
);
1253 int sd_dhcp_client_stop(sd_dhcp_client
*client
) {
1254 return client_stop(client
, DHCP_EVENT_STOP
);
1257 int sd_dhcp_client_attach_event(sd_dhcp_client
*client
, sd_event
*event
, int priority
) {
1260 assert_return(client
, -EINVAL
);
1261 assert_return(!client
->event
, -EBUSY
);
1264 client
->event
= sd_event_ref(event
);
1266 r
= sd_event_default(&client
->event
);
1271 client
->event_priority
= priority
;
1276 int sd_dhcp_client_detach_event(sd_dhcp_client
*client
) {
1277 assert_return(client
, -EINVAL
);
1279 client
->event
= sd_event_unref(client
->event
);
1284 sd_event
*sd_dhcp_client_get_event(sd_dhcp_client
*client
) {
1288 return client
->event
;
1291 void sd_dhcp_client_free(sd_dhcp_client
*client
) {
1295 sd_dhcp_client_stop(client
);
1296 sd_dhcp_client_detach_event(client
);
1298 free(client
->req_opts
);
1302 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client
*, sd_dhcp_client_free
);
1303 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_freep)
1305 int sd_dhcp_client_new(sd_dhcp_client
**ret
) {
1306 _cleanup_dhcp_client_free_ sd_dhcp_client
*client
= NULL
;
1308 assert_return(ret
, -EINVAL
);
1310 client
= new0(sd_dhcp_client
, 1);
1314 client
->state
= DHCP_STATE_INIT
;
1317 client
->attempt
= 1;
1319 client
->req_opts_size
= ELEMENTSOF(default_req_opts
);
1321 client
->req_opts
= memdup(default_req_opts
, client
->req_opts_size
);
1322 if (!client
->req_opts
)