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
36 #define client_state_machine_check(s, r) \
38 if (s != DHCP_STATE_BOUND && \
39 s != DHCP_STATE_RENEWING && \
40 s != DHCP_STATE_REBINDING) { \
50 be32_t server_address
;
60 typedef struct DHCPLease DHCPLease
;
62 struct sd_dhcp_client
{
66 sd_event_source
*timeout_resend
;
69 union sockaddr_union link
;
70 sd_event_source
*receive_message
;
72 size_t req_opts_allocated
;
75 struct ether_addr mac_addr
;
81 sd_event_source
*timeout_t1
;
82 sd_event_source
*timeout_t2
;
83 sd_event_source
*timeout_expire
;
84 sd_dhcp_client_cb_t cb
;
89 static const uint8_t default_req_opts
[] = {
90 DHCP_OPTION_SUBNET_MASK
,
92 DHCP_OPTION_HOST_NAME
,
93 DHCP_OPTION_DOMAIN_NAME
,
94 DHCP_OPTION_DOMAIN_NAME_SERVER
,
95 DHCP_OPTION_NTP_SERVER
,
98 static int client_receive_message(sd_event_source
*s
, int fd
,
99 uint32_t revents
, void *userdata
);
101 int sd_dhcp_client_set_callback(sd_dhcp_client
*client
, sd_dhcp_client_cb_t cb
,
103 assert_return(client
, -EINVAL
);
106 client
->userdata
= userdata
;
111 int sd_dhcp_client_set_request_option(sd_dhcp_client
*client
, uint8_t option
) {
114 assert_return(client
, -EINVAL
);
115 assert_return (client
->state
== DHCP_STATE_INIT
, -EBUSY
);
118 case DHCP_OPTION_PAD
:
119 case DHCP_OPTION_OVERLOAD
:
120 case DHCP_OPTION_MESSAGE_TYPE
:
121 case DHCP_OPTION_PARAMETER_REQUEST_LIST
:
122 case DHCP_OPTION_END
:
129 for (i
= 0; i
< client
->req_opts_size
; i
++)
130 if (client
->req_opts
[i
] == option
)
133 if (!GREEDY_REALLOC(client
->req_opts
, client
->req_opts_allocated
,
134 client
->req_opts_size
+ 1))
137 client
->req_opts
[client
->req_opts_size
++] = option
;
142 int sd_dhcp_client_set_request_address(sd_dhcp_client
*client
,
143 const struct in_addr
*last_addr
) {
144 assert_return(client
, -EINVAL
);
145 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
148 client
->last_addr
= last_addr
->s_addr
;
150 client
->last_addr
= INADDR_ANY
;
155 int sd_dhcp_client_set_index(sd_dhcp_client
*client
, int interface_index
) {
156 assert_return(client
, -EINVAL
);
157 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
158 assert_return(interface_index
>= -1, -EINVAL
);
160 client
->index
= interface_index
;
165 int sd_dhcp_client_set_mac(sd_dhcp_client
*client
,
166 const struct ether_addr
*addr
) {
167 assert_return(client
, -EINVAL
);
168 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
170 memcpy(&client
->mac_addr
, addr
, ETH_ALEN
);
175 int sd_dhcp_client_get_address(sd_dhcp_client
*client
, struct in_addr
*addr
) {
176 assert_return(client
, -EINVAL
);
177 assert_return(addr
, -EINVAL
);
179 client_state_machine_check (client
->state
, -EADDRNOTAVAIL
);
181 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 client_state_machine_check (client
->state
, -EADDRNOTAVAIL
);
192 if (client
->lease
->mtu
)
193 *mtu
= client
->lease
->mtu
;
200 int sd_dhcp_client_get_dns(sd_dhcp_client
*client
, struct in_addr
**addr
, size_t *addr_size
) {
201 assert_return(client
, -EINVAL
);
202 assert_return(addr
, -EINVAL
);
203 assert_return(addr_size
, -EINVAL
);
205 client_state_machine_check (client
->state
, -EADDRNOTAVAIL
);
207 if (client
->lease
->dns_size
) {
208 *addr_size
= client
->lease
->dns_size
;
209 *addr
= client
->lease
->dns
;
216 int sd_dhcp_client_get_domainname(sd_dhcp_client
*client
, const char **domainname
) {
217 assert_return(client
, -EINVAL
);
218 assert_return(domainname
, -EINVAL
);
220 client_state_machine_check (client
->state
, -EADDRNOTAVAIL
);
222 if (client
->lease
->domainname
)
223 *domainname
= client
->lease
->domainname
;
230 int sd_dhcp_client_get_hostname(sd_dhcp_client
*client
, const char **hostname
) {
231 assert_return(client
, -EINVAL
);
232 assert_return(hostname
, -EINVAL
);
234 client_state_machine_check (client
->state
, -EADDRNOTAVAIL
);
236 if (client
->lease
->hostname
)
237 *hostname
= client
->lease
->hostname
;
244 int sd_dhcp_client_get_router(sd_dhcp_client
*client
, struct in_addr
*addr
) {
245 assert_return(client
, -EINVAL
);
246 assert_return(addr
, -EINVAL
);
248 client_state_machine_check (client
->state
, -EADDRNOTAVAIL
);
250 addr
->s_addr
= client
->lease
->router
;
255 int sd_dhcp_client_get_netmask(sd_dhcp_client
*client
, struct in_addr
*addr
) {
256 assert_return(client
, -EINVAL
);
257 assert_return(addr
, -EINVAL
);
259 client_state_machine_check (client
->state
, -EADDRNOTAVAIL
);
261 addr
->s_addr
= client
->lease
->subnet_mask
;
266 static int client_notify(sd_dhcp_client
*client
, int event
) {
268 client
->cb(client
, event
, client
->userdata
);
273 static void lease_free(DHCPLease
*lease
) {
277 free(lease
->hostname
);
278 free(lease
->domainname
);
283 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease
*, lease_free
);
284 #define _cleanup_lease_free_ _cleanup_(lease_freep)
286 static int client_stop(sd_dhcp_client
*client
, int error
) {
287 assert_return(client
, -EINVAL
);
289 client
->receive_message
=
290 sd_event_source_unref(client
->receive_message
);
296 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
298 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
299 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
300 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
304 client_notify(client
, error
);
306 client
->start_time
= 0;
308 client
->state
= DHCP_STATE_INIT
;
311 lease_free(client
->lease
);
312 client
->lease
= NULL
;
318 static int client_packet_init(sd_dhcp_client
*client
, uint8_t type
,
319 DHCPMessage
*message
, uint16_t secs
,
320 uint8_t **opt
, size_t *optlen
) {
324 *opt
= (uint8_t *)(message
+ 1);
330 message
->op
= BOOTREQUEST
;
332 message
->hlen
= ETHER_ADDR_LEN
;
333 message
->xid
= htobe32(client
->xid
);
335 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
336 refuse to issue an DHCP lease if 'secs' is set to zero */
337 message
->secs
= htobe16(secs
);
339 if (client
->state
== DHCP_STATE_RENEWING
||
340 client
->state
== DHCP_STATE_REBINDING
)
341 message
->ciaddr
= client
->lease
->address
;
343 memcpy(&message
->chaddr
, &client
->mac_addr
, ETH_ALEN
);
351 err
= dhcp_option_append(opt
, optlen
, DHCP_OPTION_MESSAGE_TYPE
, 1,
356 /* Some DHCP servers will refuse to issue an DHCP lease if the Cliient
357 Identifier option is not set */
358 err
= dhcp_option_append(opt
, optlen
, DHCP_OPTION_CLIENT_IDENTIFIER
,
359 ETH_ALEN
, &client
->mac_addr
);
363 if (type
== DHCP_DISCOVER
|| type
== DHCP_REQUEST
) {
364 err
= dhcp_option_append(opt
, optlen
,
365 DHCP_OPTION_PARAMETER_REQUEST_LIST
,
366 client
->req_opts_size
,
371 /* Some DHCP servers will send bigger DHCP packets than the
372 defined default size unless the Maximum Messge Size option
373 is explicitely set */
374 max_size
= htobe16(DHCP_IP_UDP_SIZE
+ DHCP_MESSAGE_SIZE
+
375 DHCP_CLIENT_MIN_OPTIONS_SIZE
);
376 err
= dhcp_option_append(opt
, optlen
,
377 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
,
386 static uint16_t client_checksum(void *buf
, int len
) {
395 for (i
= 0; i
< len
/ 2 ; i
++)
404 sum
= (sum
& 0xffff) + (sum
>> 16);
409 static void client_append_ip_headers(DHCPPacket
*packet
, uint16_t len
) {
410 packet
->ip
.version
= IPVERSION
;
411 packet
->ip
.ihl
= DHCP_IP_SIZE
/ 4;
412 packet
->ip
.tot_len
= htobe16(len
);
414 packet
->ip
.protocol
= IPPROTO_UDP
;
415 packet
->ip
.saddr
= INADDR_ANY
;
416 packet
->ip
.daddr
= INADDR_BROADCAST
;
418 packet
->udp
.source
= htobe16(DHCP_PORT_CLIENT
);
419 packet
->udp
.dest
= htobe16(DHCP_PORT_SERVER
);
420 packet
->udp
.len
= htobe16(len
- DHCP_IP_SIZE
);
422 packet
->ip
.check
= packet
->udp
.len
;
423 packet
->udp
.check
= client_checksum(&packet
->ip
.ttl
, len
- 8);
425 packet
->ip
.ttl
= IPDEFTTL
;
426 packet
->ip
.check
= 0;
427 packet
->ip
.check
= client_checksum(&packet
->ip
, DHCP_IP_SIZE
);
430 static int client_send_discover(sd_dhcp_client
*client
, uint16_t secs
) {
432 _cleanup_free_ DHCPPacket
*discover
;
436 optlen
= DHCP_CLIENT_MIN_OPTIONS_SIZE
;
437 len
= sizeof(DHCPPacket
) + optlen
;
439 discover
= malloc0(len
);
444 err
= client_packet_init(client
, DHCP_DISCOVER
, &discover
->dhcp
,
445 secs
, &opt
, &optlen
);
449 if (client
->last_addr
!= INADDR_ANY
) {
450 err
= dhcp_option_append(&opt
, &optlen
,
451 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
452 4, &client
->last_addr
);
457 err
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
461 client_append_ip_headers(discover
, len
);
463 err
= dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
469 static int client_send_request(sd_dhcp_client
*client
, uint16_t secs
) {
470 _cleanup_free_ DHCPPacket
*request
;
475 optlen
= DHCP_CLIENT_MIN_OPTIONS_SIZE
;
476 len
= DHCP_MESSAGE_SIZE
+ optlen
;
478 request
= malloc0(len
);
482 err
= client_packet_init(client
, DHCP_REQUEST
, &request
->dhcp
, secs
,
487 if (client
->state
== DHCP_STATE_REQUESTING
) {
488 err
= dhcp_option_append(&opt
, &optlen
,
489 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
490 4, &client
->lease
->address
);
494 err
= dhcp_option_append(&opt
, &optlen
,
495 DHCP_OPTION_SERVER_IDENTIFIER
,
496 4, &client
->lease
->server_address
);
501 err
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
505 if (client
->state
== DHCP_STATE_RENEWING
) {
506 err
= dhcp_network_send_udp_socket(client
->fd
,
507 client
->lease
->server_address
,
509 len
- DHCP_IP_UDP_SIZE
);
511 client_append_ip_headers(request
, len
);
513 err
= dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
520 static uint16_t client_update_secs(sd_dhcp_client
*client
, usec_t time_now
)
522 client
->secs
= (time_now
- client
->start_time
) / USEC_PER_SEC
;
527 static int client_timeout_resend(sd_event_source
*s
, uint64_t usec
,
529 sd_dhcp_client
*client
= userdata
;
530 usec_t next_timeout
= 0;
536 assert(client
->event
);
538 switch (client
->state
) {
539 case DHCP_STATE_RENEWING
:
541 time_left
= (client
->lease
->t2
- client
->lease
->t1
)/2;
545 next_timeout
= usec
+ time_left
* USEC_PER_SEC
;
549 case DHCP_STATE_REBINDING
:
551 time_left
= (client
->lease
->lifetime
- client
->lease
->t2
)/2;
555 next_timeout
= usec
+ time_left
* USEC_PER_SEC
;
558 case DHCP_STATE_INIT
:
559 case DHCP_STATE_INIT_REBOOT
:
560 case DHCP_STATE_REBOOTING
:
561 case DHCP_STATE_SELECTING
:
562 case DHCP_STATE_REQUESTING
:
563 case DHCP_STATE_BOUND
:
565 if (client
->attempt
< 64)
566 client
->attempt
*= 2;
568 next_timeout
= usec
+ (client
->attempt
- 1) * USEC_PER_SEC
;
573 next_timeout
+= (random_u32() & 0x1fffff);
575 r
= sd_event_add_monotonic(client
->event
, next_timeout
,
577 client_timeout_resend
, client
,
578 &client
->timeout_resend
);
582 r
= sd_event_source_set_priority(client
->timeout_resend
, client
->event_priority
);
586 switch (client
->state
) {
587 case DHCP_STATE_INIT
:
589 client_update_secs(client
, usec
);
591 r
= client_send_discover(client
, client
->secs
);
593 client
->state
= DHCP_STATE_SELECTING
;
596 if (client
->attempt
>= 64)
602 case DHCP_STATE_SELECTING
:
603 client_update_secs(client
, usec
);
605 r
= client_send_discover(client
, client
->secs
);
606 if (r
< 0 && client
->attempt
>= 64)
611 case DHCP_STATE_REQUESTING
:
612 case DHCP_STATE_RENEWING
:
613 case DHCP_STATE_REBINDING
:
614 r
= client_send_request(client
, client
->secs
);
615 if (r
< 0 && client
->attempt
>= 64)
618 client
->request_sent
= usec
;
622 case DHCP_STATE_INIT_REBOOT
:
623 case DHCP_STATE_REBOOTING
:
624 case DHCP_STATE_BOUND
:
632 client_stop(client
, r
);
634 /* Errors were dealt with when stopping the client, don't spill
635 errors into the event loop handler */
639 static int client_initialize_events(sd_dhcp_client
*client
, usec_t usec
) {
643 assert(client
->event
);
645 r
= sd_event_add_io(client
->event
, client
->fd
, EPOLLIN
,
646 client_receive_message
, client
,
647 &client
->receive_message
);
651 r
= sd_event_source_set_priority(client
->receive_message
, client
->event_priority
);
655 r
= sd_event_add_monotonic(client
->event
, usec
, 0,
656 client_timeout_resend
, client
,
657 &client
->timeout_resend
);
661 r
= sd_event_source_set_priority(client
->timeout_resend
, client
->event_priority
);
665 client_stop(client
, r
);
671 static int client_timeout_expire(sd_event_source
*s
, uint64_t usec
,
673 sd_dhcp_client
*client
= userdata
;
675 client_stop(client
, DHCP_EVENT_EXPIRED
);
680 static int client_timeout_t2(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
681 sd_dhcp_client
*client
= userdata
;
684 if (client
->fd
>= 0) {
685 client
->receive_message
=
686 sd_event_source_unref(client
->receive_message
);
691 client
->state
= DHCP_STATE_REBINDING
;
694 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
);
696 client_stop(client
, r
);
702 return client_initialize_events(client
, usec
);
705 static int client_timeout_t1(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
706 sd_dhcp_client
*client
= userdata
;
709 client
->state
= DHCP_STATE_RENEWING
;
712 r
= dhcp_network_bind_udp_socket(client
->index
,
713 client
->lease
->address
);
715 client_stop(client
, r
);
721 return client_initialize_events(client
, usec
);
724 static int client_parse_options(uint8_t code
, uint8_t len
, const uint8_t *option
,
726 DHCPLease
*lease
= user_data
;
731 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
733 memcpy(&val
, option
, 4);
734 lease
->lifetime
= be32toh(val
);
739 case DHCP_OPTION_SERVER_IDENTIFIER
:
741 memcpy(&lease
->server_address
, option
, 4);
745 case DHCP_OPTION_SUBNET_MASK
:
747 memcpy(&lease
->subnet_mask
, option
, 4);
751 case DHCP_OPTION_ROUTER
:
753 memcpy(&lease
->router
, option
, 4);
757 case DHCP_OPTION_DOMAIN_NAME_SERVER
:
758 if (len
&& !(len
% 4)) {
761 lease
->dns_size
= len
/ 4;
764 lease
->dns
= new0(struct in_addr
, lease
->dns_size
);
768 for (i
= 0; i
< lease
->dns_size
; i
++) {
769 memcpy(&lease
->dns
[i
].s_addr
, option
+ 4 * i
, 4);
775 case DHCP_OPTION_INTERFACE_MTU
:
779 memcpy(&mtu
, option
, 2);
780 lease
->mtu
= be16toh(mtu
);
788 case DHCP_OPTION_DOMAIN_NAME
:
790 free(lease
->domainname
);
791 lease
->domainname
= strndup((const char *)option
, len
);
796 case DHCP_OPTION_HOST_NAME
:
798 free(lease
->hostname
);
799 lease
->hostname
= strndup((const char *)option
, len
);
804 case DHCP_OPTION_RENEWAL_T1_TIME
:
806 memcpy(&val
, option
, 4);
807 lease
->t1
= be32toh(val
);
812 case DHCP_OPTION_REBINDING_T2_TIME
:
814 memcpy(&val
, option
, 4);
815 lease
->t2
= be32toh(val
);
824 static int client_verify_headers(sd_dhcp_client
*client
, DHCPPacket
*message
,
828 if (len
< (DHCP_IP_UDP_SIZE
+ DHCP_MESSAGE_SIZE
))
831 hdrlen
= message
->ip
.ihl
* 4;
832 if (hdrlen
< 20 || hdrlen
> len
|| client_checksum(&message
->ip
,
836 if (hdrlen
+ be16toh(message
->udp
.len
) > len
)
839 if (message
->udp
.check
) {
840 message
->ip
.check
= message
->udp
.len
;
843 if (client_checksum(&message
->ip
.ttl
,
844 be16toh(message
->udp
.len
) + 12))
848 if (be16toh(message
->udp
.source
) != DHCP_PORT_SERVER
||
849 be16toh(message
->udp
.dest
) != DHCP_PORT_CLIENT
)
852 if (message
->dhcp
.op
!= BOOTREPLY
)
855 if (be32toh(message
->dhcp
.xid
) != client
->xid
)
858 if (memcmp(&message
->dhcp
.chaddr
[0], &client
->mac_addr
.ether_addr_octet
,
865 static int client_receive_offer(sd_dhcp_client
*client
, DHCPPacket
*offer
,
867 _cleanup_lease_free_ DHCPLease
*lease
= NULL
;
870 r
= client_verify_headers(client
, offer
, len
);
874 lease
= new0(DHCPLease
, 1);
878 len
= len
- DHCP_IP_UDP_SIZE
;
879 r
= dhcp_option_parse(&offer
->dhcp
, len
, client_parse_options
,
884 lease
->address
= offer
->dhcp
.yiaddr
;
886 if (lease
->address
== INADDR_ANY
||
887 lease
->server_address
== INADDR_ANY
||
888 lease
->subnet_mask
== INADDR_ANY
||
889 lease
->lifetime
== 0)
892 client
->lease
= lease
;
898 static int client_receive_ack(sd_dhcp_client
*client
, const uint8_t *buf
,
902 _cleanup_lease_free_ DHCPLease
*lease
= NULL
;
905 if (client
->state
== DHCP_STATE_RENEWING
) {
906 dhcp
= (DHCPMessage
*)buf
;
908 ack
= (DHCPPacket
*)buf
;
910 r
= client_verify_headers(client
, ack
, len
);
915 len
-= DHCP_IP_UDP_SIZE
;
918 lease
= new0(DHCPLease
, 1);
922 r
= dhcp_option_parse(dhcp
, len
, client_parse_options
, lease
);
924 return DHCP_EVENT_NO_LEASE
;
929 lease
->address
= dhcp
->yiaddr
;
931 if (lease
->address
== INADDR_ANY
||
932 lease
->server_address
== INADDR_ANY
||
933 lease
->subnet_mask
== INADDR_ANY
|| lease
->lifetime
== 0)
936 r
= DHCP_EVENT_IP_ACQUIRE
;
938 if (client
->lease
->address
!= lease
->address
||
939 client
->lease
->subnet_mask
!= lease
->subnet_mask
||
940 client
->lease
->router
!= lease
->router
) {
941 r
= DHCP_EVENT_IP_CHANGE
;
944 lease_free(client
->lease
);
947 client
->lease
= lease
;
953 static uint64_t client_compute_timeout(uint64_t request_sent
,
955 return request_sent
+ (lifetime
- 3) * USEC_PER_SEC
+
956 + (random_u32() & 0x1fffff);
959 static int client_set_lease_timeouts(sd_dhcp_client
*client
, uint64_t usec
) {
960 uint64_t next_timeout
;
964 assert(client
->event
);
966 if (client
->lease
->lifetime
< 10)
969 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
970 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
971 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
973 if (!client
->lease
->t1
)
974 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
976 next_timeout
= client_compute_timeout(client
->request_sent
,
978 if (next_timeout
< usec
)
981 r
= sd_event_add_monotonic(client
->event
, next_timeout
,
983 client_timeout_t1
, client
,
984 &client
->timeout_t1
);
988 r
= sd_event_source_set_priority(client
->timeout_t1
, client
->event_priority
);
992 if (!client
->lease
->t2
)
993 client
->lease
->t2
= client
->lease
->lifetime
* 7 / 8;
995 if (client
->lease
->t2
< client
->lease
->t1
)
998 if (client
->lease
->lifetime
< client
->lease
->t2
)
1001 next_timeout
= client_compute_timeout(client
->request_sent
,
1003 if (next_timeout
< usec
)
1006 r
= sd_event_add_monotonic(client
->event
, next_timeout
,
1008 client_timeout_t2
, client
,
1009 &client
->timeout_t2
);
1013 r
= sd_event_source_set_priority(client
->timeout_t2
, client
->event_priority
);
1017 next_timeout
= client_compute_timeout(client
->request_sent
,
1018 client
->lease
->lifetime
);
1019 if (next_timeout
< usec
)
1022 r
= sd_event_add_monotonic(client
->event
, next_timeout
,
1024 client_timeout_expire
, client
,
1025 &client
->timeout_expire
);
1029 r
= sd_event_source_set_priority(client
->timeout_expire
, client
->event_priority
);
1036 static int client_receive_message(sd_event_source
*s
, int fd
,
1037 uint32_t revents
, void *userdata
) {
1038 sd_dhcp_client
*client
= userdata
;
1039 uint8_t buf
[sizeof(DHCPPacket
) + DHCP_CLIENT_MIN_OPTIONS_SIZE
];
1040 int buflen
= sizeof(buf
);
1041 int len
, r
= 0, notify_event
= 0;
1042 DHCPPacket
*message
;
1047 assert(client
->event
);
1049 len
= read(fd
, &buf
, buflen
);
1053 r
= sd_event_get_now_monotonic(client
->event
, &time_now
);
1057 switch (client
->state
) {
1058 case DHCP_STATE_SELECTING
:
1060 message
= (DHCPPacket
*)&buf
;
1062 if (client_receive_offer(client
, message
, len
) >= 0) {
1064 client
->timeout_resend
=
1065 sd_event_source_unref(client
->timeout_resend
);
1067 client
->state
= DHCP_STATE_REQUESTING
;
1068 client
->attempt
= 1;
1070 r
= sd_event_add_monotonic(client
->event
, time_now
, 0,
1071 client_timeout_resend
,
1073 &client
->timeout_resend
);
1077 r
= sd_event_source_set_priority(client
->timeout_resend
, client
->event_priority
);
1084 case DHCP_STATE_REQUESTING
:
1085 case DHCP_STATE_RENEWING
:
1086 case DHCP_STATE_REBINDING
:
1088 r
= client_receive_ack(client
, buf
, len
);
1090 if (r
== DHCP_EVENT_NO_LEASE
)
1094 client
->timeout_resend
=
1095 sd_event_source_unref(client
->timeout_resend
);
1097 if (client
->state
== DHCP_STATE_REQUESTING
)
1098 notify_event
= DHCP_EVENT_IP_ACQUIRE
;
1099 else if (r
!= DHCP_EVENT_IP_ACQUIRE
)
1102 client
->state
= DHCP_STATE_BOUND
;
1103 client
->attempt
= 1;
1105 client
->last_addr
= client
->lease
->address
;
1107 r
= client_set_lease_timeouts(client
, time_now
);
1112 client_notify(client
, notify_event
);
1114 client
->receive_message
=
1115 sd_event_source_unref(client
->receive_message
);
1124 case DHCP_STATE_INIT
:
1125 case DHCP_STATE_INIT_REBOOT
:
1126 case DHCP_STATE_REBOOTING
:
1127 case DHCP_STATE_BOUND
:
1133 if (r
< 0 || r
== DHCP_EVENT_NO_LEASE
)
1134 return client_stop(client
, r
);
1139 int sd_dhcp_client_start(sd_dhcp_client
*client
) {
1142 assert_return(client
, -EINVAL
);
1143 assert_return(client
->event
, -EINVAL
);
1144 assert_return(client
->index
> 0, -EINVAL
);
1145 assert_return(client
->state
== DHCP_STATE_INIT
||
1146 client
->state
== DHCP_STATE_INIT_REBOOT
, -EBUSY
);
1148 client
->xid
= random_u32();
1150 r
= dhcp_network_bind_raw_socket(client
->index
, &client
->link
);
1153 client_stop(client
, r
);
1158 client
->start_time
= now(CLOCK_MONOTONIC
);
1161 return client_initialize_events(client
, client
->start_time
);
1164 int sd_dhcp_client_stop(sd_dhcp_client
*client
) {
1165 return client_stop(client
, DHCP_EVENT_STOP
);
1168 int sd_dhcp_client_attach_event(sd_dhcp_client
*client
, sd_event
*event
, int priority
) {
1171 assert_return(client
, -EINVAL
);
1172 assert_return(!client
->event
, -EBUSY
);
1175 client
->event
= sd_event_ref(event
);
1177 r
= sd_event_default(&client
->event
);
1182 client
->event_priority
= priority
;
1187 int sd_dhcp_client_detach_event(sd_dhcp_client
*client
) {
1188 assert_return(client
, -EINVAL
);
1190 client
->event
= sd_event_unref(client
->event
);
1195 sd_event
*sd_dhcp_client_get_event(sd_dhcp_client
*client
) {
1199 return client
->event
;
1202 void sd_dhcp_client_free(sd_dhcp_client
*client
) {
1206 sd_dhcp_client_stop(client
);
1207 sd_dhcp_client_detach_event(client
);
1209 free(client
->req_opts
);
1213 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client
*, sd_dhcp_client_free
);
1214 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_freep)
1216 int sd_dhcp_client_new(sd_dhcp_client
**ret
) {
1217 _cleanup_dhcp_client_free_ sd_dhcp_client
*client
= NULL
;
1219 assert_return(ret
, -EINVAL
);
1221 client
= new0(sd_dhcp_client
, 1);
1225 client
->state
= DHCP_STATE_INIT
;
1228 client
->attempt
= 1;
1230 client
->req_opts_size
= ELEMENTSOF(default_req_opts
);
1232 client
->req_opts
= memdup(default_req_opts
, client
->req_opts_size
);
1233 if (!client
->req_opts
)