]> git.proxmox.com Git - systemd.git/blame - src/libsystemd-network/sd-dhcp-client.c
Imported Upstream version 229
[systemd.git] / src / libsystemd-network / sd-dhcp-client.c
CommitLineData
60f067b4
JS
1/***
2 This file is part of systemd.
3
4 Copyright (C) 2013 Intel Corporation. All rights reserved.
5
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.
10
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.
15
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/>.
18***/
19
60f067b4 20#include <errno.h>
60f067b4
JS
21#include <net/ethernet.h>
22#include <net/if_arp.h>
db2df898
MP
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
60f067b4 26#include <sys/ioctl.h>
db2df898 27#include <linux/if_infiniband.h>
60f067b4 28
db2df898 29#include "sd-dhcp-client.h"
60f067b4 30
db2df898
MP
31#include "alloc-util.h"
32#include "async.h"
33#include "dhcp-identifier.h"
60f067b4
JS
34#include "dhcp-internal.h"
35#include "dhcp-lease-internal.h"
db2df898 36#include "dhcp-protocol.h"
4c89c718
MP
37#include "dns-domain.h"
38#include "hostname-util.h"
db2df898
MP
39#include "random-util.h"
40#include "string-util.h"
41#include "util.h"
60f067b4 42
e735f4d4 43#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
e3bff60a 44#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
5eef597e 45
4c89c718
MP
46#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
47#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
48
60f067b4 49struct sd_dhcp_client {
d9dfd233 50 unsigned n_ref;
60f067b4
JS
51
52 DHCPState state;
53 sd_event *event;
54 int event_priority;
55 sd_event_source *timeout_resend;
56 int index;
57 int fd;
58 union sockaddr_union link;
59 sd_event_source *receive_message;
5eef597e 60 bool request_broadcast;
60f067b4
JS
61 uint8_t *req_opts;
62 size_t req_opts_allocated;
63 size_t req_opts_size;
64 be32_t last_addr;
5eef597e
MP
65 uint8_t mac_addr[MAX_MAC_ADDR_LEN];
66 size_t mac_addr_len;
67 uint16_t arp_type;
e735f4d4
MP
68 struct {
69 uint8_t type;
70 union {
71 struct {
72 /* 0: Generic (non-LL) (RFC 2132) */
73 uint8_t data[MAX_CLIENT_ID_LEN];
74 } _packed_ gen;
75 struct {
76 /* 1: Ethernet Link-Layer (RFC 2132) */
77 uint8_t haddr[ETH_ALEN];
78 } _packed_ eth;
79 struct {
80 /* 2 - 254: ARP/Link-Layer (RFC 2132) */
81 uint8_t haddr[0];
82 } _packed_ ll;
83 struct {
84 /* 255: Node-specific (RFC 4361) */
85 uint32_t iaid;
86 struct duid duid;
87 } _packed_ ns;
88 struct {
89 uint8_t data[MAX_CLIENT_ID_LEN];
90 } _packed_ raw;
91 };
92 } _packed_ client_id;
f47781d8 93 size_t client_id_len;
e842803a 94 char *hostname;
5eef597e
MP
95 char *vendor_class_identifier;
96 uint32_t mtu;
60f067b4
JS
97 uint32_t xid;
98 usec_t start_time;
60f067b4
JS
99 unsigned int attempt;
100 usec_t request_sent;
101 sd_event_source *timeout_t1;
102 sd_event_source *timeout_t2;
103 sd_event_source *timeout_expire;
104 sd_dhcp_client_cb_t cb;
105 void *userdata;
106 sd_dhcp_lease *lease;
4c89c718 107 usec_t start_delay;
60f067b4
JS
108};
109
110static const uint8_t default_req_opts[] = {
4c89c718
MP
111 SD_DHCP_OPTION_SUBNET_MASK,
112 SD_DHCP_OPTION_ROUTER,
113 SD_DHCP_OPTION_HOST_NAME,
114 SD_DHCP_OPTION_DOMAIN_NAME,
115 SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
60f067b4
JS
116};
117
118static int client_receive_message_raw(sd_event_source *s, int fd,
119 uint32_t revents, void *userdata);
120static int client_receive_message_udp(sd_event_source *s, int fd,
121 uint32_t revents, void *userdata);
e842803a 122static void client_stop(sd_dhcp_client *client, int error);
60f067b4
JS
123
124int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
125 void *userdata) {
126 assert_return(client, -EINVAL);
127
128 client->cb = cb;
129 client->userdata = userdata;
130
131 return 0;
132}
133
5eef597e
MP
134int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
135 assert_return(client, -EINVAL);
136
137 client->request_broadcast = !!broadcast;
138
139 return 0;
140}
141
60f067b4
JS
142int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
143 size_t i;
144
145 assert_return(client, -EINVAL);
146 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
147 DHCP_STATE_STOPPED), -EBUSY);
148
149 switch(option) {
4c89c718
MP
150 case SD_DHCP_OPTION_PAD:
151 case SD_DHCP_OPTION_OVERLOAD:
152 case SD_DHCP_OPTION_MESSAGE_TYPE:
153 case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
154 case SD_DHCP_OPTION_END:
60f067b4
JS
155 return -EINVAL;
156
157 default:
158 break;
159 }
160
161 for (i = 0; i < client->req_opts_size; i++)
162 if (client->req_opts[i] == option)
163 return -EEXIST;
164
165 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
166 client->req_opts_size + 1))
167 return -ENOMEM;
168
169 client->req_opts[client->req_opts_size++] = option;
170
171 return 0;
172}
173
174int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
175 const struct in_addr *last_addr) {
176 assert_return(client, -EINVAL);
177 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
178 DHCP_STATE_STOPPED), -EBUSY);
179
180 if (last_addr)
181 client->last_addr = last_addr->s_addr;
182 else
183 client->last_addr = INADDR_ANY;
184
185 return 0;
186}
187
188int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
189 assert_return(client, -EINVAL);
190 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
191 DHCP_STATE_STOPPED), -EBUSY);
192 assert_return(interface_index > 0, -EINVAL);
193
194 client->index = interface_index;
195
196 return 0;
197}
198
5eef597e
MP
199int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
200 size_t addr_len, uint16_t arp_type) {
e842803a 201 DHCP_CLIENT_DONT_DESTROY(client);
60f067b4
JS
202 bool need_restart = false;
203
204 assert_return(client, -EINVAL);
205 assert_return(addr, -EINVAL);
5eef597e
MP
206 assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
207 assert_return(arp_type > 0, -EINVAL);
60f067b4 208
5eef597e
MP
209 if (arp_type == ARPHRD_ETHER)
210 assert_return(addr_len == ETH_ALEN, -EINVAL);
211 else if (arp_type == ARPHRD_INFINIBAND)
212 assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
213 else
214 return -EINVAL;
215
216 if (client->mac_addr_len == addr_len &&
217 memcmp(&client->mac_addr, addr, addr_len) == 0)
60f067b4
JS
218 return 0;
219
220 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
221 log_dhcp_client(client, "Changing MAC address on running DHCP "
222 "client, restarting");
223 need_restart = true;
6300502b 224 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
60f067b4
JS
225 }
226
5eef597e
MP
227 memcpy(&client->mac_addr, addr, addr_len);
228 client->mac_addr_len = addr_len;
229 client->arp_type = arp_type;
230
f47781d8
MP
231 if (need_restart && client->state != DHCP_STATE_STOPPED)
232 sd_dhcp_client_start(client);
233
234 return 0;
235}
236
237int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
238 const uint8_t **data, size_t *data_len) {
239
240 assert_return(client, -EINVAL);
241 assert_return(type, -EINVAL);
242 assert_return(data, -EINVAL);
243 assert_return(data_len, -EINVAL);
244
245 *type = 0;
246 *data = NULL;
247 *data_len = 0;
248 if (client->client_id_len) {
e735f4d4 249 *type = client->client_id.type;
f47781d8 250 *data = client->client_id.raw.data;
e735f4d4 251 *data_len = client->client_id_len - sizeof(client->client_id.type);
f47781d8
MP
252 }
253
254 return 0;
255}
256
257int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
258 const uint8_t *data, size_t data_len) {
259 DHCP_CLIENT_DONT_DESTROY(client);
260 bool need_restart = false;
261
262 assert_return(client, -EINVAL);
263 assert_return(data, -EINVAL);
264 assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
265
266 switch (type) {
267 case ARPHRD_ETHER:
268 if (data_len != ETH_ALEN)
269 return -EINVAL;
270 break;
271 case ARPHRD_INFINIBAND:
272 if (data_len != INFINIBAND_ALEN)
273 return -EINVAL;
274 break;
275 default:
276 break;
277 }
278
e735f4d4
MP
279 if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
280 client->client_id.type == type &&
f47781d8
MP
281 memcmp(&client->client_id.raw.data, data, data_len) == 0)
282 return 0;
283
284 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
285 log_dhcp_client(client, "Changing client ID on running DHCP "
286 "client, restarting");
287 need_restart = true;
6300502b 288 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
f47781d8
MP
289 }
290
e735f4d4 291 client->client_id.type = type;
f47781d8 292 memcpy(&client->client_id.raw.data, data, data_len);
e735f4d4 293 client->client_id_len = data_len + sizeof (client->client_id.type);
60f067b4
JS
294
295 if (need_restart && client->state != DHCP_STATE_STOPPED)
296 sd_dhcp_client_start(client);
297
298 return 0;
299}
300
e842803a
MB
301int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
302 const char *hostname) {
303 char *new_hostname = NULL;
304
305 assert_return(client, -EINVAL);
306
4c89c718
MP
307 if (!hostname_is_valid(hostname, false) && !dns_name_is_valid(hostname))
308 return -EINVAL;
309
e842803a
MB
310 if (streq_ptr(client->hostname, hostname))
311 return 0;
312
313 if (hostname) {
314 new_hostname = strdup(hostname);
315 if (!new_hostname)
316 return -ENOMEM;
317 }
318
319 free(client->hostname);
320 client->hostname = new_hostname;
321
322 return 0;
323}
324
5eef597e
MP
325int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client,
326 const char *vci) {
327 char *new_vci = NULL;
328
329 assert_return(client, -EINVAL);
330
331 new_vci = strdup(vci);
332 if (!new_vci)
333 return -ENOMEM;
334
335 free(client->vendor_class_identifier);
336
337 client->vendor_class_identifier = new_vci;
338
339 return 0;
340}
341
342int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
343 assert_return(client, -EINVAL);
344 assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
345
346 client->mtu = mtu;
347
348 return 0;
349}
350
60f067b4
JS
351int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
352 assert_return(client, -EINVAL);
353 assert_return(ret, -EINVAL);
354
355 if (client->state != DHCP_STATE_BOUND &&
356 client->state != DHCP_STATE_RENEWING &&
357 client->state != DHCP_STATE_REBINDING)
358 return -EADDRNOTAVAIL;
359
13d276d0 360 *ret = client->lease;
60f067b4
JS
361
362 return 0;
363}
364
e842803a
MB
365static void client_notify(sd_dhcp_client *client, int event) {
366 if (client->cb)
60f067b4 367 client->cb(client, event, client->userdata);
60f067b4
JS
368}
369
370static int client_initialize(sd_dhcp_client *client) {
371 assert_return(client, -EINVAL);
372
373 client->receive_message =
374 sd_event_source_unref(client->receive_message);
375
376 client->fd = asynchronous_close(client->fd);
377
378 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
379
380 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
381 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
382 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
383
384 client->attempt = 1;
385
386 client->state = DHCP_STATE_INIT;
387 client->xid = 0;
388
d9dfd233 389 client->lease = sd_dhcp_lease_unref(client->lease);
60f067b4
JS
390
391 return 0;
392}
393
e842803a
MB
394static void client_stop(sd_dhcp_client *client, int error) {
395 assert(client);
60f067b4
JS
396
397 if (error < 0)
398 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
6300502b 399 else if (error == SD_DHCP_CLIENT_EVENT_STOP)
5eef597e
MP
400 log_dhcp_client(client, "STOPPED");
401 else
402 log_dhcp_client(client, "STOPPED: Unknown event");
60f067b4 403
e842803a 404 client_notify(client, error);
60f067b4 405
e842803a 406 client_initialize(client);
60f067b4
JS
407}
408
409static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
410 uint8_t type, size_t *_optlen, size_t *_optoffset) {
411 _cleanup_free_ DHCPPacket *packet;
412 size_t optlen, optoffset, size;
413 be16_t max_size;
f47781d8
MP
414 usec_t time_now;
415 uint16_t secs;
60f067b4
JS
416 int r;
417
418 assert(client);
f47781d8 419 assert(client->start_time);
60f067b4
JS
420 assert(ret);
421 assert(_optlen);
422 assert(_optoffset);
423 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
424
425 optlen = DHCP_MIN_OPTIONS_SIZE;
426 size = sizeof(DHCPPacket) + optlen;
427
428 packet = malloc0(size);
429 if (!packet)
430 return -ENOMEM;
431
432 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
5eef597e 433 client->arp_type, optlen, &optoffset);
60f067b4
JS
434 if (r < 0)
435 return r;
436
437 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
438 refuse to issue an DHCP lease if 'secs' is set to zero */
f47781d8
MP
439 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
440 if (r < 0)
441 return r;
442 assert(time_now >= client->start_time);
443
444 /* seconds between sending first and last DISCOVER
445 * must always be strictly positive to deal with broken servers */
446 secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
447 packet->dhcp.secs = htobe16(secs);
60f067b4
JS
448
449 /* RFC2132 section 4.1
450 A client that cannot receive unicast IP datagrams until its protocol
451 software has been configured with an IP address SHOULD set the
452 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
453 DHCPREQUEST messages that client sends. The BROADCAST bit will
454 provide a hint to the DHCP server and BOOTP relay agent to broadcast
5eef597e
MP
455 any messages to the client on the client's subnet.
456
457 Note: some interfaces needs this to be enabled, but some networks
458 needs this to be disabled as broadcasts are filteretd, so this
459 needs to be configurable */
460 if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
461 packet->dhcp.flags = htobe16(0x8000);
60f067b4
JS
462
463 /* RFC2132 section 4.1.1:
464 The client MUST include its hardware address in the ’chaddr’ field, if
5eef597e
MP
465 necessary for delivery of DHCP reply messages. Non-Ethernet
466 interfaces will leave 'chaddr' empty and use the client identifier
467 instead (eg, RFC 4390 section 2.1).
60f067b4 468 */
5eef597e
MP
469 if (client->arp_type == ARPHRD_ETHER)
470 memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
60f067b4 471
e735f4d4
MP
472 /* If no client identifier exists, construct an RFC 4361-compliant one */
473 if (client->client_id_len == 0) {
474 size_t duid_len;
475
476 client->client_id.type = 255;
477
478 r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid);
479 if (r < 0)
480 return r;
481
482 r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len);
483 if (r < 0)
484 return r;
485
486 client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
f47781d8
MP
487 }
488
60f067b4
JS
489 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
490 Identifier option is not set */
f47781d8
MP
491 if (client->client_id_len) {
492 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
4c89c718 493 SD_DHCP_OPTION_CLIENT_IDENTIFIER,
f47781d8 494 client->client_id_len,
e735f4d4 495 &client->client_id);
f47781d8
MP
496 if (r < 0)
497 return r;
498 }
60f067b4
JS
499
500 /* RFC2131 section 3.5:
501 in its initial DHCPDISCOVER or DHCPREQUEST message, a
502 client may provide the server with a list of specific
503 parameters the client is interested in. If the client
504 includes a list of parameters in a DHCPDISCOVER message,
505 it MUST include that list in any subsequent DHCPREQUEST
506 messages.
507 */
508 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
4c89c718 509 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
60f067b4
JS
510 client->req_opts_size, client->req_opts);
511 if (r < 0)
512 return r;
513
514 /* RFC2131 section 3.5:
515 The client SHOULD include the ’maximum DHCP message size’ option to
516 let the server know how large the server may make its DHCP messages.
517
518 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
519 than the defined default size unless the Maximum Messge Size option
e735f4d4 520 is explicitly set
5eef597e
MP
521
522 RFC3442 "Requirements to Avoid Sizing Constraints":
523 Because a full routing table can be quite large, the standard 576
524 octet maximum size for a DHCP message may be too short to contain
525 some legitimate Classless Static Route options. Because of this,
526 clients implementing the Classless Static Route option SHOULD send a
527 Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
528 stack is capable of receiving larger IP datagrams. In this case, the
529 client SHOULD set the value of this option to at least the MTU of the
530 interface that the client is configuring. The client MAY set the
531 value of this option higher, up to the size of the largest UDP packet
532 it is prepared to accept. (Note that the value specified in the
533 Maximum DHCP Message Size option is the total maximum packet size,
534 including IP and UDP headers.)
60f067b4
JS
535 */
536 max_size = htobe16(size);
5eef597e 537 r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
4c89c718 538 SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
60f067b4
JS
539 2, &max_size);
540 if (r < 0)
541 return r;
542
543 *_optlen = optlen;
544 *_optoffset = optoffset;
545 *ret = packet;
546 packet = NULL;
547
548 return 0;
549}
550
4c89c718
MP
551static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t *optoffset,
552 const char *fqdn) {
553 uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
554 int r;
555
556 buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
557 DHCP_FQDN_FLAG_E; /* Canonical wire format */
558 buffer[1] = 0; /* RCODE1 (deprecated) */
559 buffer[2] = 0; /* RCODE2 (deprecated) */
560
561 r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false);
562 if (r > 0)
563 r = dhcp_option_append(message, optlen, optoffset, 0,
564 SD_DHCP_OPTION_FQDN, 3 + r, buffer);
565
566 return r;
567}
568
60f067b4
JS
569static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
570 size_t len) {
571 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
572 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
573
574 return dhcp_network_send_raw_socket(client->fd, &client->link,
575 packet, len);
576}
577
578static int client_send_discover(sd_dhcp_client *client) {
579 _cleanup_free_ DHCPPacket *discover = NULL;
580 size_t optoffset, optlen;
60f067b4
JS
581 int r;
582
583 assert(client);
584 assert(client->state == DHCP_STATE_INIT ||
585 client->state == DHCP_STATE_SELECTING);
586
60f067b4
JS
587 r = client_message_init(client, &discover, DHCP_DISCOVER,
588 &optlen, &optoffset);
589 if (r < 0)
590 return r;
591
592 /* the client may suggest values for the network address
593 and lease time in the DHCPDISCOVER message. The client may include
594 the ’requested IP address’ option to suggest that a particular IP
595 address be assigned, and may include the ’IP address lease time’
596 option to suggest the lease time it would like.
597 */
598 if (client->last_addr != INADDR_ANY) {
599 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
4c89c718 600 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
60f067b4
JS
601 4, &client->last_addr);
602 if (r < 0)
603 return r;
604 }
605
e842803a 606 if (client->hostname) {
4c89c718
MP
607 /* According to RFC 4702 "clients that send the Client FQDN option in
608 their messages MUST NOT also send the Host Name option". Just send
609 one of the two depending on the hostname type.
610 */
611 if (dns_name_is_single_label(client->hostname)) {
612 /* it is unclear from RFC 2131 if client should send hostname in
613 DHCPDISCOVER but dhclient does and so we do as well
614 */
615 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
616 SD_DHCP_OPTION_HOST_NAME,
617 strlen(client->hostname), client->hostname);
618 } else
619 r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
620 client->hostname);
e842803a
MB
621 if (r < 0)
622 return r;
623 }
624
5eef597e
MP
625 if (client->vendor_class_identifier) {
626 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
4c89c718 627 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
5eef597e
MP
628 strlen(client->vendor_class_identifier),
629 client->vendor_class_identifier);
630 if (r < 0)
631 return r;
632 }
633
60f067b4 634 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
4c89c718 635 SD_DHCP_OPTION_END, 0, NULL);
e842803a
MB
636 if (r < 0)
637 return r;
60f067b4
JS
638
639 /* We currently ignore:
640 The client SHOULD wait a random time between one and ten seconds to
641 desynchronize the use of DHCP at startup.
642 */
643 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
644 if (r < 0)
645 return r;
646
647 log_dhcp_client(client, "DISCOVER");
648
649 return 0;
650}
651
652static int client_send_request(sd_dhcp_client *client) {
e842803a 653 _cleanup_free_ DHCPPacket *request = NULL;
60f067b4
JS
654 size_t optoffset, optlen;
655 int r;
656
657 r = client_message_init(client, &request, DHCP_REQUEST,
658 &optlen, &optoffset);
659 if (r < 0)
660 return r;
661
662 switch (client->state) {
663 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
664 SELECTING should be REQUESTING)
665 */
666
667 case DHCP_STATE_REQUESTING:
668 /* Client inserts the address of the selected server in ’server
669 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
670 filled in with the yiaddr value from the chosen DHCPOFFER.
671 */
672
673 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
4c89c718 674 SD_DHCP_OPTION_SERVER_IDENTIFIER,
60f067b4
JS
675 4, &client->lease->server_address);
676 if (r < 0)
677 return r;
678
679 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
4c89c718 680 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
60f067b4
JS
681 4, &client->lease->address);
682 if (r < 0)
683 return r;
684
685 break;
686
687 case DHCP_STATE_INIT_REBOOT:
688 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
689 option MUST be filled in with client’s notion of its previously
690 assigned address. ’ciaddr’ MUST be zero.
691 */
692 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
4c89c718 693 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
60f067b4
JS
694 4, &client->last_addr);
695 if (r < 0)
696 return r;
697 break;
698
699 case DHCP_STATE_RENEWING:
700 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
701 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
702 client’s IP address.
703 */
704
705 /* fall through */
706 case DHCP_STATE_REBINDING:
707 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
708 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
709 client’s IP address.
710
711 This message MUST be broadcast to the 0xffffffff IP broadcast address.
712 */
713 request->dhcp.ciaddr = client->lease->address;
714
715 break;
716
717 case DHCP_STATE_INIT:
718 case DHCP_STATE_SELECTING:
719 case DHCP_STATE_REBOOTING:
720 case DHCP_STATE_BOUND:
721 case DHCP_STATE_STOPPED:
722 return -EINVAL;
723 }
724
e842803a 725 if (client->hostname) {
4c89c718
MP
726 if (dns_name_is_single_label(client->hostname))
727 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
728 SD_DHCP_OPTION_HOST_NAME,
729 strlen(client->hostname), client->hostname);
730 else
731 r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
732 client->hostname);
e842803a
MB
733 if (r < 0)
734 return r;
735 }
736
60f067b4 737 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
4c89c718 738 SD_DHCP_OPTION_END, 0, NULL);
60f067b4
JS
739 if (r < 0)
740 return r;
741
742 if (client->state == DHCP_STATE_RENEWING) {
743 r = dhcp_network_send_udp_socket(client->fd,
744 client->lease->server_address,
745 DHCP_PORT_SERVER,
746 &request->dhcp,
747 sizeof(DHCPMessage) + optoffset);
748 } else {
749 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
750 }
751 if (r < 0)
752 return r;
753
754 switch (client->state) {
755 case DHCP_STATE_REQUESTING:
756 log_dhcp_client(client, "REQUEST (requesting)");
757 break;
758 case DHCP_STATE_INIT_REBOOT:
759 log_dhcp_client(client, "REQUEST (init-reboot)");
760 break;
761 case DHCP_STATE_RENEWING:
762 log_dhcp_client(client, "REQUEST (renewing)");
763 break;
764 case DHCP_STATE_REBINDING:
765 log_dhcp_client(client, "REQUEST (rebinding)");
766 break;
767 default:
768 log_dhcp_client(client, "REQUEST (invalid)");
769 break;
770 }
771
772 return 0;
773}
774
775static int client_start(sd_dhcp_client *client);
776
777static int client_timeout_resend(sd_event_source *s, uint64_t usec,
778 void *userdata) {
779 sd_dhcp_client *client = userdata;
e842803a 780 DHCP_CLIENT_DONT_DESTROY(client);
60f067b4
JS
781 usec_t next_timeout = 0;
782 uint64_t time_now;
783 uint32_t time_left;
784 int r;
785
786 assert(s);
787 assert(client);
788 assert(client->event);
789
5eef597e 790 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
60f067b4
JS
791 if (r < 0)
792 goto error;
793
794 switch (client->state) {
795 case DHCP_STATE_RENEWING:
796
797 time_left = (client->lease->t2 - client->lease->t1) / 2;
798 if (time_left < 60)
799 time_left = 60;
800
801 next_timeout = time_now + time_left * USEC_PER_SEC;
802
803 break;
804
805 case DHCP_STATE_REBINDING:
806
807 time_left = (client->lease->lifetime - client->lease->t2) / 2;
808 if (time_left < 60)
809 time_left = 60;
810
811 next_timeout = time_now + time_left * USEC_PER_SEC;
812 break;
813
814 case DHCP_STATE_REBOOTING:
815 /* start over as we did not receive a timely ack or nak */
816 r = client_initialize(client);
817 if (r < 0)
818 goto error;
819
820 r = client_start(client);
821 if (r < 0)
822 goto error;
823 else {
824 log_dhcp_client(client, "REBOOTED");
825 return 0;
826 }
827
828 case DHCP_STATE_INIT:
829 case DHCP_STATE_INIT_REBOOT:
830 case DHCP_STATE_SELECTING:
831 case DHCP_STATE_REQUESTING:
832 case DHCP_STATE_BOUND:
833
834 if (client->attempt < 64)
835 client->attempt *= 2;
836
837 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
838
839 break;
840
841 case DHCP_STATE_STOPPED:
842 r = -EINVAL;
843 goto error;
844 }
845
846 next_timeout += (random_u32() & 0x1fffff);
847
848 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
849
850 r = sd_event_add_time(client->event,
851 &client->timeout_resend,
5eef597e 852 clock_boottime_or_monotonic(),
60f067b4
JS
853 next_timeout, 10 * USEC_PER_MSEC,
854 client_timeout_resend, client);
855 if (r < 0)
856 goto error;
857
858 r = sd_event_source_set_priority(client->timeout_resend,
859 client->event_priority);
860 if (r < 0)
861 goto error;
862
f47781d8 863 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
5eef597e
MP
864 if (r < 0)
865 goto error;
866
60f067b4
JS
867 switch (client->state) {
868 case DHCP_STATE_INIT:
869 r = client_send_discover(client);
870 if (r >= 0) {
871 client->state = DHCP_STATE_SELECTING;
872 client->attempt = 1;
873 } else {
874 if (client->attempt >= 64)
875 goto error;
876 }
877
878 break;
879
880 case DHCP_STATE_SELECTING:
881 r = client_send_discover(client);
882 if (r < 0 && client->attempt >= 64)
883 goto error;
884
885 break;
886
887 case DHCP_STATE_INIT_REBOOT:
888 case DHCP_STATE_REQUESTING:
889 case DHCP_STATE_RENEWING:
890 case DHCP_STATE_REBINDING:
891 r = client_send_request(client);
892 if (r < 0 && client->attempt >= 64)
893 goto error;
894
895 if (client->state == DHCP_STATE_INIT_REBOOT)
896 client->state = DHCP_STATE_REBOOTING;
897
898 client->request_sent = time_now;
899
900 break;
901
902 case DHCP_STATE_REBOOTING:
903 case DHCP_STATE_BOUND:
904
905 break;
906
907 case DHCP_STATE_STOPPED:
908 r = -EINVAL;
909 goto error;
910 }
911
912 return 0;
913
914error:
915 client_stop(client, r);
916
917 /* Errors were dealt with when stopping the client, don't spill
918 errors into the event loop handler */
919 return 0;
920}
921
5eef597e
MP
922static int client_initialize_io_events(sd_dhcp_client *client,
923 sd_event_io_handler_t io_callback) {
60f067b4
JS
924 int r;
925
926 assert(client);
927 assert(client->event);
928
929 r = sd_event_add_io(client->event, &client->receive_message,
930 client->fd, EPOLLIN, io_callback,
931 client);
932 if (r < 0)
933 goto error;
934
935 r = sd_event_source_set_priority(client->receive_message,
936 client->event_priority);
937 if (r < 0)
938 goto error;
939
f47781d8 940 r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
5eef597e
MP
941 if (r < 0)
942 goto error;
943
944error:
945 if (r < 0)
946 client_stop(client, r);
947
948 return 0;
949}
950
951static int client_initialize_time_events(sd_dhcp_client *client) {
4c89c718 952 uint64_t usec = 0;
5eef597e
MP
953 int r;
954
955 assert(client);
956 assert(client->event);
957
60f067b4
JS
958 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
959
4c89c718
MP
960 if (client->start_delay) {
961 sd_event_now(client->event, clock_boottime_or_monotonic(), &usec);
962 usec += client->start_delay;
963 }
964
60f067b4
JS
965 r = sd_event_add_time(client->event,
966 &client->timeout_resend,
5eef597e 967 clock_boottime_or_monotonic(),
4c89c718 968 usec, 0,
60f067b4
JS
969 client_timeout_resend, client);
970 if (r < 0)
971 goto error;
972
973 r = sd_event_source_set_priority(client->timeout_resend,
974 client->event_priority);
86f210e9
MP
975 if (r < 0)
976 goto error;
60f067b4 977
f47781d8 978 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
5eef597e
MP
979 if (r < 0)
980 goto error;
981
60f067b4
JS
982error:
983 if (r < 0)
984 client_stop(client, r);
985
986 return 0;
987
988}
989
5eef597e
MP
990static int client_initialize_events(sd_dhcp_client *client,
991 sd_event_io_handler_t io_callback) {
992 client_initialize_io_events(client, io_callback);
993 client_initialize_time_events(client);
994
995 return 0;
996}
997
4c89c718 998static int client_start_delayed(sd_dhcp_client *client) {
60f067b4
JS
999 int r;
1000
1001 assert_return(client, -EINVAL);
1002 assert_return(client->event, -EINVAL);
1003 assert_return(client->index > 0, -EINVAL);
1004 assert_return(client->fd < 0, -EBUSY);
1005 assert_return(client->xid == 0, -EINVAL);
1006 assert_return(client->state == DHCP_STATE_INIT ||
1007 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
1008
1009 client->xid = random_u32();
1010
5eef597e
MP
1011 r = dhcp_network_bind_raw_socket(client->index, &client->link,
1012 client->xid, client->mac_addr,
1013 client->mac_addr_len, client->arp_type);
60f067b4
JS
1014 if (r < 0) {
1015 client_stop(client, r);
1016 return r;
1017 }
1018 client->fd = r;
1019
f47781d8 1020 if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT)
5eef597e 1021 client->start_time = now(clock_boottime_or_monotonic());
60f067b4
JS
1022
1023 return client_initialize_events(client, client_receive_message_raw);
1024}
1025
4c89c718
MP
1026static int client_start(sd_dhcp_client *client) {
1027 client->start_delay = 0;
1028 return client_start_delayed(client);
1029}
1030
60f067b4
JS
1031static int client_timeout_expire(sd_event_source *s, uint64_t usec,
1032 void *userdata) {
1033 sd_dhcp_client *client = userdata;
e842803a 1034 DHCP_CLIENT_DONT_DESTROY(client);
60f067b4
JS
1035
1036 log_dhcp_client(client, "EXPIRED");
1037
6300502b 1038 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
60f067b4
JS
1039
1040 /* lease was lost, start over if not freed or stopped in callback */
e842803a 1041 if (client->state != DHCP_STATE_STOPPED) {
60f067b4
JS
1042 client_initialize(client);
1043 client_start(client);
1044 }
1045
1046 return 0;
1047}
1048
1049static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
1050 sd_dhcp_client *client = userdata;
e842803a 1051 DHCP_CLIENT_DONT_DESTROY(client);
60f067b4
JS
1052 int r;
1053
1054 client->receive_message = sd_event_source_unref(client->receive_message);
1055 client->fd = asynchronous_close(client->fd);
1056
1057 client->state = DHCP_STATE_REBINDING;
1058 client->attempt = 1;
1059
5eef597e
MP
1060 r = dhcp_network_bind_raw_socket(client->index, &client->link,
1061 client->xid, client->mac_addr,
1062 client->mac_addr_len, client->arp_type);
60f067b4
JS
1063 if (r < 0) {
1064 client_stop(client, r);
1065 return 0;
1066 }
1067 client->fd = r;
1068
1069 return client_initialize_events(client, client_receive_message_raw);
1070}
1071
1072static int client_timeout_t1(sd_event_source *s, uint64_t usec,
1073 void *userdata) {
1074 sd_dhcp_client *client = userdata;
e842803a 1075 DHCP_CLIENT_DONT_DESTROY(client);
60f067b4
JS
1076
1077 client->state = DHCP_STATE_RENEWING;
1078 client->attempt = 1;
1079
5eef597e 1080 return client_initialize_time_events(client);
60f067b4
JS
1081}
1082
1083static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
1084 size_t len) {
4c89c718 1085 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
60f067b4
JS
1086 int r;
1087
1088 r = dhcp_lease_new(&lease);
1089 if (r < 0)
1090 return r;
1091
f47781d8
MP
1092 if (client->client_id_len) {
1093 r = dhcp_lease_set_client_id(lease,
e735f4d4 1094 (uint8_t *) &client->client_id,
f47781d8
MP
1095 client->client_id_len);
1096 if (r < 0)
1097 return r;
1098 }
1099
4c89c718 1100 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
60f067b4 1101 if (r != DHCP_OFFER) {
5eef597e 1102 log_dhcp_client(client, "received message was not an OFFER, ignoring");
60f067b4
JS
1103 return -ENOMSG;
1104 }
1105
1106 lease->next_server = offer->siaddr;
60f067b4
JS
1107 lease->address = offer->yiaddr;
1108
d9dfd233
MP
1109 if (lease->address == 0 ||
1110 lease->server_address == 0 ||
60f067b4 1111 lease->lifetime == 0) {
d9dfd233 1112 log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring");
60f067b4
JS
1113 return -ENOMSG;
1114 }
1115
d9dfd233 1116 if (!lease->have_subnet_mask) {
60f067b4
JS
1117 r = dhcp_lease_set_default_subnet_mask(lease);
1118 if (r < 0) {
5eef597e 1119 log_dhcp_client(client, "received lease lacks subnet "
60f067b4
JS
1120 "mask, and a fallback one can not be "
1121 "generated, ignoring");
1122 return -ENOMSG;
1123 }
1124 }
1125
1126 sd_dhcp_lease_unref(client->lease);
1127 client->lease = lease;
1128 lease = NULL;
1129
1130 log_dhcp_client(client, "OFFER");
1131
1132 return 0;
1133}
1134
5eef597e
MP
1135static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
1136 size_t len) {
1137 int r;
1138
4c89c718 1139 r = dhcp_option_parse(force, len, NULL, NULL, NULL);
5eef597e
MP
1140 if (r != DHCP_FORCERENEW)
1141 return -ENOMSG;
1142
1143 log_dhcp_client(client, "FORCERENEW");
1144
1145 return 0;
1146}
1147
60f067b4
JS
1148static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
1149 size_t len) {
4c89c718
MP
1150 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
1151 _cleanup_free_ char *error_message = NULL;
60f067b4
JS
1152 int r;
1153
1154 r = dhcp_lease_new(&lease);
1155 if (r < 0)
1156 return r;
1157
f47781d8
MP
1158 if (client->client_id_len) {
1159 r = dhcp_lease_set_client_id(lease,
e735f4d4 1160 (uint8_t *) &client->client_id,
f47781d8
MP
1161 client->client_id_len);
1162 if (r < 0)
1163 return r;
1164 }
1165
4c89c718 1166 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
60f067b4 1167 if (r == DHCP_NAK) {
4c89c718 1168 log_dhcp_client(client, "NAK: %s", strna(error_message));
5eef597e 1169 return -EADDRNOTAVAIL;
60f067b4
JS
1170 }
1171
1172 if (r != DHCP_ACK) {
5eef597e 1173 log_dhcp_client(client, "received message was not an ACK, ignoring");
60f067b4
JS
1174 return -ENOMSG;
1175 }
1176
1177 lease->next_server = ack->siaddr;
1178
1179 lease->address = ack->yiaddr;
1180
1181 if (lease->address == INADDR_ANY ||
1182 lease->server_address == INADDR_ANY ||
1183 lease->lifetime == 0) {
5eef597e 1184 log_dhcp_client(client, "received lease lacks address, server "
60f067b4
JS
1185 "address or lease lifetime, ignoring");
1186 return -ENOMSG;
1187 }
1188
1189 if (lease->subnet_mask == INADDR_ANY) {
1190 r = dhcp_lease_set_default_subnet_mask(lease);
1191 if (r < 0) {
5eef597e 1192 log_dhcp_client(client, "received lease lacks subnet "
60f067b4
JS
1193 "mask, and a fallback one can not be "
1194 "generated, ignoring");
1195 return -ENOMSG;
1196 }
1197 }
1198
6300502b 1199 r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
60f067b4
JS
1200 if (client->lease) {
1201 if (client->lease->address != lease->address ||
1202 client->lease->subnet_mask != lease->subnet_mask ||
1203 client->lease->router != lease->router) {
6300502b 1204 r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
e842803a 1205 } else
6300502b 1206 r = SD_DHCP_CLIENT_EVENT_RENEW;
60f067b4
JS
1207
1208 client->lease = sd_dhcp_lease_unref(client->lease);
1209 }
1210
1211 client->lease = lease;
1212 lease = NULL;
1213
1214 log_dhcp_client(client, "ACK");
1215
1216 return r;
1217}
1218
d9dfd233 1219static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) {
60f067b4
JS
1220 assert(client);
1221 assert(client->request_sent);
d9dfd233 1222 assert(lifetime > 0);
60f067b4 1223
d9dfd233
MP
1224 if (lifetime > 3)
1225 lifetime -= 3;
1226 else
1227 lifetime = 0;
1228
1229 return client->request_sent + (lifetime * USEC_PER_SEC * factor) +
60f067b4
JS
1230 + (random_u32() & 0x1fffff);
1231}
1232
1233static int client_set_lease_timeouts(sd_dhcp_client *client) {
1234 usec_t time_now;
1235 uint64_t lifetime_timeout;
1236 uint64_t t2_timeout;
1237 uint64_t t1_timeout;
1238 char time_string[FORMAT_TIMESPAN_MAX];
1239 int r;
1240
1241 assert(client);
1242 assert(client->event);
1243 assert(client->lease);
1244 assert(client->lease->lifetime);
1245
1246 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1247 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1248 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
1249
1250 /* don't set timers for infinite leases */
1251 if (client->lease->lifetime == 0xffffffff)
1252 return 0;
1253
5eef597e 1254 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
60f067b4
JS
1255 if (r < 0)
1256 return r;
1257 assert(client->request_sent <= time_now);
1258
1259 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1260 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
d9dfd233 1261 if (client->lease->t1 > 0 && client->lease->t2 > 0) {
60f067b4
JS
1262 /* both T1 and T2 are given */
1263 if (client->lease->t1 < client->lease->t2 &&
1264 client->lease->t2 < client->lease->lifetime) {
1265 /* they are both valid */
1266 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1267 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1268 } else {
1269 /* discard both */
1270 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1271 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1272 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1273 client->lease->t1 = client->lease->lifetime / 2;
1274 }
d9dfd233 1275 } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) {
60f067b4
JS
1276 /* only T2 is given, and it is valid */
1277 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1278 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1279 client->lease->t1 = client->lease->lifetime / 2;
1280 if (t2_timeout <= t1_timeout) {
1281 /* the computed T1 would be invalid, so discard T2 */
1282 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1283 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1284 }
d9dfd233 1285 } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) {
60f067b4
JS
1286 /* only T1 is given, and it is valid */
1287 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1288 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1289 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1290 if (t2_timeout <= t1_timeout) {
1291 /* the computed T2 would be invalid, so discard T1 */
1292 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1293 client->lease->t2 = client->lease->lifetime / 2;
1294 }
1295 } else {
1296 /* fall back to the default timeouts */
1297 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1298 client->lease->t1 = client->lease->lifetime / 2;
1299 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1300 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1301 }
1302
1303 /* arm lifetime timeout */
1304 r = sd_event_add_time(client->event, &client->timeout_expire,
5eef597e 1305 clock_boottime_or_monotonic(),
60f067b4
JS
1306 lifetime_timeout, 10 * USEC_PER_MSEC,
1307 client_timeout_expire, client);
1308 if (r < 0)
1309 return r;
1310
1311 r = sd_event_source_set_priority(client->timeout_expire,
1312 client->event_priority);
1313 if (r < 0)
1314 return r;
1315
f47781d8 1316 r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime");
5eef597e
MP
1317 if (r < 0)
1318 return r;
1319
60f067b4 1320 log_dhcp_client(client, "lease expires in %s",
db2df898 1321 format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
60f067b4
JS
1322
1323 /* don't arm earlier timeouts if this has already expired */
1324 if (lifetime_timeout <= time_now)
1325 return 0;
1326
1327 /* arm T2 timeout */
1328 r = sd_event_add_time(client->event,
1329 &client->timeout_t2,
5eef597e 1330 clock_boottime_or_monotonic(),
60f067b4
JS
1331 t2_timeout,
1332 10 * USEC_PER_MSEC,
1333 client_timeout_t2, client);
1334 if (r < 0)
1335 return r;
1336
1337 r = sd_event_source_set_priority(client->timeout_t2,
1338 client->event_priority);
1339 if (r < 0)
1340 return r;
1341
f47781d8 1342 r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout");
5eef597e
MP
1343 if (r < 0)
1344 return r;
1345
60f067b4 1346 log_dhcp_client(client, "T2 expires in %s",
db2df898 1347 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
60f067b4
JS
1348
1349 /* don't arm earlier timeout if this has already expired */
1350 if (t2_timeout <= time_now)
1351 return 0;
1352
1353 /* arm T1 timeout */
1354 r = sd_event_add_time(client->event,
1355 &client->timeout_t1,
5eef597e 1356 clock_boottime_or_monotonic(),
60f067b4
JS
1357 t1_timeout, 10 * USEC_PER_MSEC,
1358 client_timeout_t1, client);
1359 if (r < 0)
1360 return r;
1361
1362 r = sd_event_source_set_priority(client->timeout_t1,
1363 client->event_priority);
1364 if (r < 0)
1365 return r;
1366
f47781d8 1367 r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer");
5eef597e
MP
1368 if (r < 0)
1369 return r;
1370
60f067b4 1371 log_dhcp_client(client, "T1 expires in %s",
db2df898 1372 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
60f067b4
JS
1373
1374 return 0;
1375}
1376
1377static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1378 int len) {
e842803a 1379 DHCP_CLIENT_DONT_DESTROY(client);
4c89c718 1380 char time_string[FORMAT_TIMESPAN_MAX];
60f067b4
JS
1381 int r = 0, notify_event = 0;
1382
1383 assert(client);
1384 assert(client->event);
1385 assert(message);
1386
60f067b4
JS
1387 switch (client->state) {
1388 case DHCP_STATE_SELECTING:
1389
1390 r = client_handle_offer(client, message, len);
1391 if (r >= 0) {
1392
1393 client->timeout_resend =
1394 sd_event_source_unref(client->timeout_resend);
1395
1396 client->state = DHCP_STATE_REQUESTING;
1397 client->attempt = 1;
1398
1399 r = sd_event_add_time(client->event,
1400 &client->timeout_resend,
5eef597e 1401 clock_boottime_or_monotonic(),
60f067b4
JS
1402 0, 0,
1403 client_timeout_resend, client);
1404 if (r < 0)
1405 goto error;
1406
1407 r = sd_event_source_set_priority(client->timeout_resend,
1408 client->event_priority);
1409 if (r < 0)
1410 goto error;
5eef597e 1411
f47781d8 1412 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
5eef597e
MP
1413 if (r < 0)
1414 goto error;
60f067b4
JS
1415 } else if (r == -ENOMSG)
1416 /* invalid message, let's ignore it */
1417 return 0;
1418
1419 break;
1420
1421 case DHCP_STATE_REBOOTING:
1422 case DHCP_STATE_REQUESTING:
1423 case DHCP_STATE_RENEWING:
1424 case DHCP_STATE_REBINDING:
1425
1426 r = client_handle_ack(client, message, len);
5eef597e 1427 if (r >= 0) {
4c89c718 1428 client->start_delay = 0;
60f067b4
JS
1429 client->timeout_resend =
1430 sd_event_source_unref(client->timeout_resend);
f47781d8
MP
1431 client->receive_message =
1432 sd_event_source_unref(client->receive_message);
1433 client->fd = asynchronous_close(client->fd);
60f067b4
JS
1434
1435 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1436 DHCP_STATE_REBOOTING))
6300502b
MP
1437 notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1438 else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
60f067b4
JS
1439 notify_event = r;
1440
1441 client->state = DHCP_STATE_BOUND;
1442 client->attempt = 1;
1443
1444 client->last_addr = client->lease->address;
1445
1446 r = client_set_lease_timeouts(client);
e735f4d4
MP
1447 if (r < 0) {
1448 log_dhcp_client(client, "could not set lease timeouts");
60f067b4 1449 goto error;
e735f4d4 1450 }
60f067b4 1451
5eef597e
MP
1452 r = dhcp_network_bind_udp_socket(client->lease->address,
1453 DHCP_PORT_CLIENT);
1454 if (r < 0) {
1455 log_dhcp_client(client, "could not bind UDP socket");
1456 goto error;
1457 }
1458
1459 client->fd = r;
1460
1461 client_initialize_io_events(client, client_receive_message_udp);
1462
60f067b4 1463 if (notify_event) {
e842803a
MB
1464 client_notify(client, notify_event);
1465 if (client->state == DHCP_STATE_STOPPED)
60f067b4
JS
1466 return 0;
1467 }
1468
5eef597e
MP
1469 } else if (r == -EADDRNOTAVAIL) {
1470 /* got a NAK, let's restart the client */
1471 client->timeout_resend =
1472 sd_event_source_unref(client->timeout_resend);
1473
1474 r = client_initialize(client);
1475 if (r < 0)
1476 goto error;
1477
4c89c718 1478 r = client_start_delayed(client);
5eef597e
MP
1479 if (r < 0)
1480 goto error;
1481
4c89c718
MP
1482 log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1483 client->start_delay, USEC_PER_SEC));
1484
1485 client->start_delay = CLAMP(client->start_delay * 2,
1486 RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
5eef597e
MP
1487
1488 return 0;
1489 } else if (r == -ENOMSG)
1490 /* invalid message, let's ignore it */
1491 return 0;
1492
1493 break;
1494
1495 case DHCP_STATE_BOUND:
1496 r = client_handle_forcerenew(client, message, len);
1497 if (r >= 0) {
1498 r = client_timeout_t1(NULL, 0, client);
1499 if (r < 0)
1500 goto error;
60f067b4
JS
1501 } else if (r == -ENOMSG)
1502 /* invalid message, let's ignore it */
1503 return 0;
1504
1505 break;
1506
1507 case DHCP_STATE_INIT:
1508 case DHCP_STATE_INIT_REBOOT:
60f067b4
JS
1509
1510 break;
1511
1512 case DHCP_STATE_STOPPED:
1513 r = -EINVAL;
1514 goto error;
1515 }
1516
1517error:
5eef597e 1518 if (r < 0)
60f067b4
JS
1519 client_stop(client, r);
1520
1521 return r;
1522}
1523
1524static int client_receive_message_udp(sd_event_source *s, int fd,
1525 uint32_t revents, void *userdata) {
1526 sd_dhcp_client *client = userdata;
1527 _cleanup_free_ DHCPMessage *message = NULL;
1528 int buflen = 0, len, r;
5eef597e
MP
1529 const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
1530 const struct ether_addr *expected_chaddr = NULL;
1531 uint8_t expected_hlen = 0;
60f067b4
JS
1532
1533 assert(s);
1534 assert(client);
1535
1536 r = ioctl(fd, FIONREAD, &buflen);
1537 if (r < 0)
4c89c718
MP
1538 return -errno;
1539 else if (buflen < 0)
60f067b4
JS
1540 /* this can't be right */
1541 return -EIO;
1542
1543 message = malloc0(buflen);
1544 if (!message)
1545 return -ENOMEM;
1546
1547 len = read(fd, message, buflen);
1548 if (len < 0) {
4c89c718
MP
1549 if (errno == EAGAIN || errno == EINTR)
1550 return 0;
1551
1552 log_dhcp_client(client, "Could not receive message from UDP socket: %m");
1553 return -errno;
5eef597e 1554 } else if ((size_t)len < sizeof(DHCPMessage)) {
4c89c718 1555 log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
5eef597e
MP
1556 return 0;
1557 }
1558
1559 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
4c89c718 1560 log_dhcp_client(client, "Not a DHCP message: ignoring");
5eef597e
MP
1561 return 0;
1562 }
1563
1564 if (message->op != BOOTREPLY) {
4c89c718 1565 log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
5eef597e
MP
1566 return 0;
1567 }
1568
1569 if (message->htype != client->arp_type) {
4c89c718 1570 log_dhcp_client(client, "Packet type does not match client type");
5eef597e
MP
1571 return 0;
1572 }
1573
1574 if (client->arp_type == ARPHRD_ETHER) {
1575 expected_hlen = ETH_ALEN;
1576 expected_chaddr = (const struct ether_addr *) &client->mac_addr;
1577 } else {
db2df898 1578 /* Non-Ethernet links expect zero chaddr */
5eef597e
MP
1579 expected_hlen = 0;
1580 expected_chaddr = &zero_mac;
1581 }
1582
1583 if (message->hlen != expected_hlen) {
4c89c718 1584 log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
5eef597e
MP
1585 return 0;
1586 }
1587
1588 if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
4c89c718 1589 log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
5eef597e
MP
1590 return 0;
1591 }
1592
1593 if (client->state != DHCP_STATE_BOUND &&
1594 be32toh(message->xid) != client->xid) {
1595 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1596 so ignore the xid in this case */
4c89c718 1597 log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
5eef597e 1598 be32toh(message->xid), client->xid);
60f067b4 1599 return 0;
5eef597e 1600 }
60f067b4
JS
1601
1602 return client_handle_message(client, message, len);
1603}
1604
1605static int client_receive_message_raw(sd_event_source *s, int fd,
1606 uint32_t revents, void *userdata) {
1607 sd_dhcp_client *client = userdata;
1608 _cleanup_free_ DHCPPacket *packet = NULL;
1609 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1610 struct iovec iov = {};
1611 struct msghdr msg = {
1612 .msg_iov = &iov,
1613 .msg_iovlen = 1,
1614 .msg_control = cmsgbuf,
1615 .msg_controllen = sizeof(cmsgbuf),
1616 };
1617 struct cmsghdr *cmsg;
1618 bool checksum = true;
1619 int buflen = 0, len, r;
1620
1621 assert(s);
1622 assert(client);
1623
1624 r = ioctl(fd, FIONREAD, &buflen);
1625 if (r < 0)
4c89c718
MP
1626 return -errno;
1627 else if (buflen < 0)
60f067b4
JS
1628 /* this can't be right */
1629 return -EIO;
1630
1631 packet = malloc0(buflen);
1632 if (!packet)
1633 return -ENOMEM;
1634
1635 iov.iov_base = packet;
1636 iov.iov_len = buflen;
1637
1638 len = recvmsg(fd, &msg, 0);
1639 if (len < 0) {
4c89c718
MP
1640 if (errno == EAGAIN || errno == EINTR)
1641 return 0;
1642
1643 log_dhcp_client(client, "Could not receive message from raw socket: %m");
1644
1645 return -errno;
60f067b4
JS
1646 } else if ((size_t)len < sizeof(DHCPPacket))
1647 return 0;
1648
86f210e9 1649 CMSG_FOREACH(cmsg, &msg) {
60f067b4
JS
1650 if (cmsg->cmsg_level == SOL_PACKET &&
1651 cmsg->cmsg_type == PACKET_AUXDATA &&
1652 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1653 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1654
1655 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1656 break;
1657 }
1658 }
1659
1660 r = dhcp_packet_verify_headers(packet, len, checksum);
1661 if (r < 0)
1662 return 0;
1663
1664 len -= DHCP_IP_UDP_SIZE;
1665
1666 return client_handle_message(client, &packet->dhcp, len);
1667}
1668
1669int sd_dhcp_client_start(sd_dhcp_client *client) {
1670 int r;
1671
1672 assert_return(client, -EINVAL);
1673
1674 r = client_initialize(client);
1675 if (r < 0)
1676 return r;
1677
1678 if (client->last_addr)
1679 client->state = DHCP_STATE_INIT_REBOOT;
1680
1681 r = client_start(client);
1682 if (r >= 0)
e735f4d4 1683 log_dhcp_client(client, "STARTED on ifindex %i", client->index);
60f067b4
JS
1684
1685 return r;
1686}
1687
1688int sd_dhcp_client_stop(sd_dhcp_client *client) {
e842803a
MB
1689 DHCP_CLIENT_DONT_DESTROY(client);
1690
60f067b4
JS
1691 assert_return(client, -EINVAL);
1692
6300502b 1693 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
e842803a 1694 client->state = DHCP_STATE_STOPPED;
60f067b4
JS
1695
1696 return 0;
1697}
1698
1699int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1700 int priority) {
1701 int r;
1702
1703 assert_return(client, -EINVAL);
1704 assert_return(!client->event, -EBUSY);
1705
1706 if (event)
1707 client->event = sd_event_ref(event);
1708 else {
1709 r = sd_event_default(&client->event);
1710 if (r < 0)
1711 return 0;
1712 }
1713
1714 client->event_priority = priority;
1715
1716 return 0;
1717}
1718
1719int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1720 assert_return(client, -EINVAL);
1721
1722 client->event = sd_event_unref(client->event);
1723
1724 return 0;
1725}
1726
1727sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1728 if (!client)
1729 return NULL;
1730
1731 return client->event;
1732}
1733
1734sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
d9dfd233
MP
1735
1736 if (!client)
1737 return NULL;
1738
1739 assert(client->n_ref >= 1);
1740 client->n_ref++;
60f067b4
JS
1741
1742 return client;
1743}
1744
1745sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
60f067b4 1746
d9dfd233
MP
1747 if (!client)
1748 return NULL;
60f067b4 1749
d9dfd233
MP
1750 assert(client->n_ref >= 1);
1751 client->n_ref--;
60f067b4 1752
d9dfd233
MP
1753 if (client->n_ref > 0)
1754 return NULL;
60f067b4 1755
d9dfd233 1756 log_dhcp_client(client, "FREE");
60f067b4 1757
d9dfd233
MP
1758 client_initialize(client);
1759
1760 client->receive_message = sd_event_source_unref(client->receive_message);
1761
1762 sd_dhcp_client_detach_event(client);
1763
1764 sd_dhcp_lease_unref(client->lease);
1765
1766 free(client->req_opts);
1767 free(client->hostname);
1768 free(client->vendor_class_identifier);
1769 free(client);
60f067b4 1770
e842803a 1771 return NULL;
60f067b4
JS
1772}
1773
60f067b4 1774int sd_dhcp_client_new(sd_dhcp_client **ret) {
4c89c718 1775 _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
60f067b4
JS
1776
1777 assert_return(ret, -EINVAL);
1778
1779 client = new0(sd_dhcp_client, 1);
1780 if (!client)
1781 return -ENOMEM;
1782
d9dfd233 1783 client->n_ref = 1;
60f067b4
JS
1784 client->state = DHCP_STATE_INIT;
1785 client->index = -1;
1786 client->fd = -1;
1787 client->attempt = 1;
5eef597e 1788 client->mtu = DHCP_DEFAULT_MIN_SIZE;
60f067b4
JS
1789
1790 client->req_opts_size = ELEMENTSOF(default_req_opts);
1791
1792 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1793 if (!client->req_opts)
1794 return -ENOMEM;
1795
1796 *ret = client;
1797 client = NULL;
1798
1799 return 0;
1800}