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>
29 #include "dhcp-protocol.h"
30 #include "dhcp-internal.h"
31 #include "sd-dhcp-client.h"
33 #define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
38 uint32_t server_address
;
43 typedef struct DHCPLease DHCPLease
;
45 struct sd_dhcp_client
{
48 sd_event_source
*timeout_resend
;
51 union sockaddr_union link
;
52 sd_event_source
*receive_message
;
56 struct ether_addr mac_addr
;
63 static const uint8_t default_req_opts
[] = {
64 DHCP_OPTION_SUBNET_MASK
,
66 DHCP_OPTION_HOST_NAME
,
67 DHCP_OPTION_DOMAIN_NAME
,
68 DHCP_OPTION_DOMAIN_NAME_SERVER
,
69 DHCP_OPTION_NTP_SERVER
,
72 int sd_dhcp_client_set_request_option(sd_dhcp_client
*client
, uint8_t option
)
76 assert_return(client
, -EINVAL
);
77 assert_return (client
->state
== DHCP_STATE_INIT
, -EBUSY
);
81 case DHCP_OPTION_OVERLOAD
:
82 case DHCP_OPTION_MESSAGE_TYPE
:
83 case DHCP_OPTION_PARAMETER_REQUEST_LIST
:
91 for (i
= 0; i
< client
->req_opts_size
; i
++)
92 if (client
->req_opts
[i
] == option
)
95 if (!GREEDY_REALLOC(client
->req_opts
, client
->req_opts_size
,
96 client
->req_opts_size
+ 1))
99 client
->req_opts
[client
->req_opts_size
- 1] = option
;
104 int sd_dhcp_client_set_request_address(sd_dhcp_client
*client
,
105 const struct in_addr
*last_addr
)
107 assert_return(client
, -EINVAL
);
108 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
111 client
->last_addr
= last_addr
->s_addr
;
113 client
->last_addr
= INADDR_ANY
;
118 int sd_dhcp_client_set_index(sd_dhcp_client
*client
, int interface_index
)
120 assert_return(client
, -EINVAL
);
121 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
122 assert_return(interface_index
>= -1, -EINVAL
);
124 client
->index
= interface_index
;
129 int sd_dhcp_client_set_mac(sd_dhcp_client
*client
,
130 const struct ether_addr
*addr
)
132 assert_return(client
, -EINVAL
);
133 assert_return(client
->state
== DHCP_STATE_INIT
, -EBUSY
);
135 memcpy(&client
->mac_addr
, addr
, ETH_ALEN
);
140 static int client_notify(sd_dhcp_client
*client
, int event
)
145 static int client_stop(sd_dhcp_client
*client
, int error
)
147 assert_return(client
, -EINVAL
);
148 assert_return(client
->state
!= DHCP_STATE_INIT
&&
149 client
->state
!= DHCP_STATE_INIT_REBOOT
, -EALREADY
);
151 client
->receive_message
=
152 sd_event_source_unref(client
->receive_message
);
158 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
162 switch (client
->state
) {
164 case DHCP_STATE_INIT
:
165 case DHCP_STATE_SELECTING
:
166 case DHCP_STATE_REQUESTING
:
168 client
->start_time
= 0;
169 client
->state
= DHCP_STATE_INIT
;
172 case DHCP_STATE_INIT_REBOOT
:
173 case DHCP_STATE_REBOOTING
:
174 case DHCP_STATE_BOUND
:
175 case DHCP_STATE_RENEWING
:
176 case DHCP_STATE_REBINDING
:
183 client
->lease
= NULL
;
189 static int client_packet_init(sd_dhcp_client
*client
, uint8_t type
,
190 DHCPMessage
*message
, uint16_t secs
,
191 uint8_t **opt
, size_t *optlen
)
196 *opt
= (uint8_t *)(message
+ 1);
202 message
->op
= BOOTREQUEST
;
204 message
->hlen
= ETHER_ADDR_LEN
;
205 message
->xid
= htobe32(client
->xid
);
207 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
208 refuse to issue an DHCP lease if 'secs' is set to zero */
209 message
->secs
= htobe16(secs
);
211 memcpy(&message
->chaddr
, &client
->mac_addr
, ETH_ALEN
);
219 err
= dhcp_option_append(opt
, optlen
, DHCP_OPTION_MESSAGE_TYPE
, 1,
224 /* Some DHCP servers will refuse to issue an DHCP lease if the Cliient
225 Identifier option is not set */
226 err
= dhcp_option_append(opt
, optlen
, DHCP_OPTION_CLIENT_IDENTIFIER
,
227 ETH_ALEN
, &client
->mac_addr
);
231 if (type
== DHCP_DISCOVER
|| type
== DHCP_REQUEST
) {
232 err
= dhcp_option_append(opt
, optlen
,
233 DHCP_OPTION_PARAMETER_REQUEST_LIST
,
234 client
->req_opts_size
,
239 /* Some DHCP servers will send bigger DHCP packets than the
240 defined default size unless the Maximum Messge Size option
241 is explicitely set */
242 max_size
= htobe16(DHCP_IP_UDP_SIZE
+ DHCP_MESSAGE_SIZE
+
243 DHCP_CLIENT_MIN_OPTIONS_SIZE
);
244 err
= dhcp_option_append(opt
, optlen
,
245 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
,
254 static uint16_t client_checksum(void *buf
, int len
)
264 for (i
= 0; i
< len
/ 2 ; i
++)
272 return ~((sum
& 0xffff) + (sum
>> 16));
275 static void client_append_ip_headers(DHCPPacket
*packet
, uint16_t len
)
277 packet
->ip
.version
= IPVERSION
;
278 packet
->ip
.ihl
= DHCP_IP_SIZE
/ 4;
279 packet
->ip
.tot_len
= htobe16(len
);
281 packet
->ip
.protocol
= IPPROTO_UDP
;
282 packet
->ip
.saddr
= INADDR_ANY
;
283 packet
->ip
.daddr
= INADDR_BROADCAST
;
285 packet
->udp
.source
= htobe16(DHCP_PORT_CLIENT
);
286 packet
->udp
.dest
= htobe16(DHCP_PORT_SERVER
);
287 packet
->udp
.len
= htobe16(len
- DHCP_IP_SIZE
);
289 packet
->ip
.check
= packet
->udp
.len
;
290 packet
->udp
.check
= client_checksum(&packet
->ip
.ttl
, len
- 8);
292 packet
->ip
.ttl
= IPDEFTTL
;
293 packet
->ip
.check
= 0;
294 packet
->ip
.check
= client_checksum(&packet
->ip
, DHCP_IP_SIZE
);
297 static int client_send_discover(sd_dhcp_client
*client
, uint16_t secs
)
300 _cleanup_free_ DHCPPacket
*discover
;
304 optlen
= DHCP_CLIENT_MIN_OPTIONS_SIZE
;
305 len
= sizeof(DHCPPacket
) + optlen
;
307 discover
= malloc0(len
);
312 err
= client_packet_init(client
, DHCP_DISCOVER
, &discover
->dhcp
,
313 secs
, &opt
, &optlen
);
317 if (client
->last_addr
!= INADDR_ANY
) {
318 err
= dhcp_option_append(&opt
, &optlen
,
319 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
320 4, &client
->last_addr
);
325 err
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
329 client_append_ip_headers(discover
, len
);
331 err
= dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
337 static int client_send_request(sd_dhcp_client
*client
, uint16_t secs
)
339 _cleanup_free_ DHCPPacket
*request
;
344 optlen
= DHCP_CLIENT_MIN_OPTIONS_SIZE
;
345 len
= DHCP_MESSAGE_SIZE
+ optlen
;
347 request
= malloc0(len
);
351 err
= client_packet_init(client
, DHCP_REQUEST
, &request
->dhcp
, secs
,
356 if (client
->state
== DHCP_STATE_REQUESTING
) {
357 err
= dhcp_option_append(&opt
, &optlen
,
358 DHCP_OPTION_REQUESTED_IP_ADDRESS
,
359 4, &client
->lease
->address
);
363 err
= dhcp_option_append(&opt
, &optlen
,
364 DHCP_OPTION_SERVER_IDENTIFIER
,
365 4, &client
->lease
->server_address
);
370 err
= dhcp_option_append(&opt
, &optlen
, DHCP_OPTION_END
, 0, NULL
);
374 client_append_ip_headers(request
, len
);
376 err
= dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
382 static int client_timeout_resend(sd_event_source
*s
, uint64_t usec
,
385 sd_dhcp_client
*client
= userdata
;
390 secs
= (usec
- client
->start_time
) / USEC_PER_SEC
;
392 if (client
->attempt
< 64)
393 client
->attempt
*= 2;
395 next_timeout
= usec
+ (client
->attempt
- 1) * USEC_PER_SEC
+
396 (random_u() & 0x1fffff);
398 err
= sd_event_add_monotonic(client
->event
, next_timeout
,
400 client_timeout_resend
, client
,
401 &client
->timeout_resend
);
405 switch (client
->state
) {
406 case DHCP_STATE_INIT
:
407 err
= client_send_discover(client
, secs
);
409 client
->state
= DHCP_STATE_SELECTING
;
412 if (client
->attempt
>= 64)
418 case DHCP_STATE_SELECTING
:
419 err
= client_send_discover(client
, secs
);
420 if (err
< 0 && client
->attempt
>= 64)
425 case DHCP_STATE_REQUESTING
:
426 err
= client_send_request(client
, secs
);
427 if (err
< 0 && client
->attempt
>= 64)
432 case DHCP_STATE_INIT_REBOOT
:
433 case DHCP_STATE_REBOOTING
:
434 case DHCP_STATE_BOUND
:
435 case DHCP_STATE_RENEWING
:
436 case DHCP_STATE_REBINDING
:
444 client_stop(client
, err
);
446 /* Errors were dealt with when stopping the client, don't spill
447 errors into the event loop handler */
451 static int client_parse_offer(uint8_t code
, uint8_t len
, const uint8_t *option
,
454 DHCPLease
*lease
= user_data
;
459 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
461 memcpy(&val
, option
, 4);
462 lease
->lifetime
= be32toh(val
);
467 case DHCP_OPTION_SERVER_IDENTIFIER
:
469 memcpy(&lease
->server_address
, option
, 4);
473 case DHCP_OPTION_SUBNET_MASK
:
475 memcpy(&lease
->subnet_mask
, option
, 4);
479 case DHCP_OPTION_ROUTER
:
481 memcpy(&lease
->router
, option
, 4);
489 static int client_verify_headers(sd_dhcp_client
*client
, DHCPPacket
*message
,
494 if (len
< (DHCP_IP_UDP_SIZE
+ DHCP_MESSAGE_SIZE
))
497 hdrlen
= message
->ip
.ihl
* 4;
498 if (hdrlen
< 20 || hdrlen
> len
|| client_checksum(&message
->ip
,
502 message
->ip
.check
= message
->udp
.len
;
505 if (hdrlen
+ be16toh(message
->udp
.len
) > len
||
506 client_checksum(&message
->ip
.ttl
, be16toh(message
->udp
.len
) + 12))
509 if (be16toh(message
->udp
.source
) != DHCP_PORT_SERVER
||
510 be16toh(message
->udp
.dest
) != DHCP_PORT_CLIENT
)
513 if (message
->dhcp
.op
!= BOOTREPLY
)
516 if (be32toh(message
->dhcp
.xid
) != client
->xid
)
519 if (memcmp(&message
->dhcp
.chaddr
[0], &client
->mac_addr
.ether_addr_octet
,
526 static int client_receive_offer(sd_dhcp_client
*client
, DHCPPacket
*offer
,
532 err
= client_verify_headers(client
, offer
, len
);
536 lease
= new0(DHCPLease
, 1);
540 len
= len
- DHCP_IP_UDP_SIZE
;
541 if (dhcp_option_parse(&offer
->dhcp
, len
, client_parse_offer
,
542 lease
) != DHCP_OFFER
)
545 lease
->address
= offer
->dhcp
.yiaddr
;
547 if (lease
->address
== INADDR_ANY
||
548 lease
->server_address
== INADDR_ANY
||
549 lease
->subnet_mask
== INADDR_ANY
||
550 lease
->lifetime
== 0)
553 client
->lease
= lease
;
563 static int client_receive_ack(sd_dhcp_client
*client
, DHCPPacket
*offer
,
569 r
= client_verify_headers(client
, offer
, len
);
573 lease
= new0(DHCPLease
, 1);
577 len
= len
- DHCP_IP_UDP_SIZE
;
578 r
= dhcp_option_parse(&offer
->dhcp
, len
, client_parse_offer
, lease
);
583 lease
->address
= offer
->dhcp
.yiaddr
;
585 if (lease
->address
== INADDR_ANY
||
586 lease
->server_address
== INADDR_ANY
||
587 lease
->subnet_mask
== INADDR_ANY
|| lease
->lifetime
== 0) {
592 r
= DHCP_EVENT_IP_ACQUIRE
;
594 if (client
->lease
->address
!= lease
->address
||
595 client
->lease
->subnet_mask
!= lease
->subnet_mask
||
596 client
->lease
->router
!= lease
->router
) {
597 r
= DHCP_EVENT_IP_CHANGE
;
603 client
->lease
= lease
;
613 static int client_receive_raw_message(sd_event_source
*s
, int fd
,
614 uint32_t revents
, void *userdata
)
616 sd_dhcp_client
*client
= userdata
;
617 uint8_t buf
[sizeof(DHCPPacket
) + DHCP_CLIENT_MIN_OPTIONS_SIZE
];
618 int buflen
= sizeof(buf
);
623 len
= read(fd
, &buf
, buflen
);
627 r
= sd_event_get_now_monotonic(client
->event
, &time_now
);
631 message
= (DHCPPacket
*)&buf
;
633 switch (client
->state
) {
634 case DHCP_STATE_SELECTING
:
636 if (client_receive_offer(client
, message
, len
) >= 0) {
638 client
->timeout_resend
=
639 sd_event_source_unref(client
->timeout_resend
);
641 client
->state
= DHCP_STATE_REQUESTING
;
644 r
= sd_event_add_monotonic(client
->event
, time_now
, 0,
645 client_timeout_resend
,
647 &client
->timeout_resend
);
654 case DHCP_STATE_REQUESTING
:
656 r
= client_receive_ack(client
, message
, len
);
657 if (r
== DHCP_EVENT_NO_LEASE
)
661 client
->timeout_resend
=
662 sd_event_source_unref(client
->timeout_resend
);
664 client
->state
= DHCP_STATE_BOUND
;
667 client
->last_addr
= client
->lease
->address
;
669 client_notify(client
, DHCP_EVENT_IP_ACQUIRE
);
673 client
->receive_message
=
674 sd_event_source_unref(client
->receive_message
);
678 case DHCP_STATE_INIT
:
679 case DHCP_STATE_INIT_REBOOT
:
680 case DHCP_STATE_REBOOTING
:
681 case DHCP_STATE_BOUND
:
682 case DHCP_STATE_RENEWING
:
683 case DHCP_STATE_REBINDING
:
690 return client_stop(client
, r
);
695 int sd_dhcp_client_start(sd_dhcp_client
*client
)
699 assert_return(client
, -EINVAL
);
700 assert_return(client
->index
>= 0, -EINVAL
);
701 assert_return(client
->state
== DHCP_STATE_INIT
||
702 client
->state
== DHCP_STATE_INIT_REBOOT
, -EBUSY
);
704 client
->xid
= random_u();
706 client
->fd
= dhcp_network_bind_raw_socket(client
->index
,
709 if (client
->fd
< 0) {
714 err
= sd_event_add_io(client
->event
, client
->fd
, EPOLLIN
,
715 client_receive_raw_message
, client
,
716 &client
->receive_message
);
720 client
->start_time
= now(CLOCK_MONOTONIC
);
721 err
= sd_event_add_monotonic(client
->event
, client
->start_time
, 0,
722 client_timeout_resend
, client
,
723 &client
->timeout_resend
);
730 client_stop(client
, err
);
735 int sd_dhcp_client_stop(sd_dhcp_client
*client
)
737 return client_stop(client
, 0);
740 sd_dhcp_client
*sd_dhcp_client_new(sd_event
*event
)
742 sd_dhcp_client
*client
;
744 assert_return(event
, NULL
);
746 client
= new0(sd_dhcp_client
, 1);
750 client
->event
= sd_event_ref(event
);
751 client
->state
= DHCP_STATE_INIT
;
756 client
->req_opts_size
= ELEMENTSOF(default_req_opts
);
758 client
->req_opts
= memdup(default_req_opts
, client
->req_opts_size
);
759 if (!client
->req_opts
) {