]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-client.c
sd-dhcp-client: remove unnecessary cleanup function
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-client.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
011feef8 2/***
810adae9 3 Copyright © 2013 Intel Corporation. All rights reserved.
011feef8
PF
4***/
5
011feef8 6#include <errno.h>
46a66b79 7#include <net/ethernet.h>
3b7ca119 8#include <net/if_arp.h>
07630cea
LP
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
5266a81e 12#include <sys/ioctl.h>
07630cea 13#include <linux/if_infiniband.h>
011feef8 14
07630cea 15#include "sd-dhcp-client.h"
011feef8 16
b5efdb8a 17#include "alloc-util.h"
07630cea
LP
18#include "async.h"
19#include "dhcp-identifier.h"
46a66b79 20#include "dhcp-internal.h"
fe8db0c5 21#include "dhcp-lease-internal.h"
07630cea 22#include "dhcp-protocol.h"
23873e25 23#include "dns-domain.h"
a3fa4287 24#include "event-util.h"
23873e25 25#include "hostname-util.h"
cb310866 26#include "io-util.h"
0a970718 27#include "memory-util.h"
07630cea
LP
28#include "random-util.h"
29#include "string-util.h"
af1c0de0 30#include "strv.h"
011feef8 31
5bac5235 32#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
dd168445 33#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
76253e73 34
1d1a3e0a
BG
35#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
36#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
37
cb29c156
SS
38struct sd_dhcp_option {
39 unsigned n_ref;
40
41 uint8_t option;
42 void *data;
43 size_t length;
44};
45
011feef8 46struct sd_dhcp_client {
3733eec3 47 unsigned n_ref;
e5b04c8d 48
011feef8 49 DHCPState state;
d3d8ac2f 50 sd_event *event;
b25ef18b 51 int event_priority;
d3d8ac2f 52 sd_event_source *timeout_resend;
2f8e7633 53 int ifindex;
8c00042c 54 int fd;
9faed222 55 uint16_t port;
8c00042c
PF
56 union sockaddr_union link;
57 sd_event_source *receive_message;
f5de5b00 58 bool request_broadcast;
011feef8 59 uint8_t *req_opts;
7a7c74ca 60 size_t req_opts_allocated;
011feef8 61 size_t req_opts_size;
db3d2358 62 bool anonymize;
3b349af6 63 be32_t last_addr;
76253e73
DW
64 uint8_t mac_addr[MAX_MAC_ADDR_LEN];
65 size_t mac_addr_len;
66 uint16_t arp_type;
5bac5235
TG
67 struct {
68 uint8_t type;
69 union {
70 struct {
71 /* 0: Generic (non-LL) (RFC 2132) */
72 uint8_t data[MAX_CLIENT_ID_LEN];
73 } _packed_ gen;
74 struct {
75 /* 1: Ethernet Link-Layer (RFC 2132) */
76 uint8_t haddr[ETH_ALEN];
77 } _packed_ eth;
78 struct {
79 /* 2 - 254: ARP/Link-Layer (RFC 2132) */
80 uint8_t haddr[0];
81 } _packed_ ll;
82 struct {
83 /* 255: Node-specific (RFC 4361) */
413708d1 84 be32_t iaid;
5bac5235
TG
85 struct duid duid;
86 } _packed_ ns;
87 struct {
88 uint8_t data[MAX_CLIENT_ID_LEN];
89 } _packed_ raw;
90 };
91 } _packed_ client_id;
ba6c0fd6 92 size_t client_id_len;
4cc7a82c 93 char *hostname;
edb85f0d 94 char *vendor_class_identifier;
af1c0de0 95 char **user_class;
324f8187 96 uint32_t mtu;
46a66b79 97 uint32_t xid;
d3d8ac2f 98 usec_t start_time;
715cedfb
SS
99 uint64_t attempt;
100 uint64_t max_attempts;
cb29c156 101 OrderedHashmap *options;
51debc1e
PF
102 usec_t request_sent;
103 sd_event_source *timeout_t1;
104 sd_event_source *timeout_t2;
105 sd_event_source *timeout_expire;
45aa74c7 106 sd_dhcp_client_callback_t callback;
751246ee 107 void *userdata;
a6cc569e 108 sd_dhcp_lease *lease;
1d1a3e0a 109 usec_t start_delay;
afe42aef 110 int ip_service_type;
011feef8
PF
111};
112
113static const uint8_t default_req_opts[] = {
22805d92
BG
114 SD_DHCP_OPTION_SUBNET_MASK,
115 SD_DHCP_OPTION_ROUTER,
116 SD_DHCP_OPTION_HOST_NAME,
117 SD_DHCP_OPTION_DOMAIN_NAME,
118 SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
011feef8
PF
119};
120
db3d2358 121/* RFC7844 section 3:
122 MAY contain the Parameter Request List option.
123 RFC7844 section 3.6:
124 The client intending to protect its privacy SHOULD only request a
125 minimal number of options in the PRL and SHOULD also randomly shuffle
126 the ordering of option codes in the PRL. If this random ordering
127 cannot be implemented, the client MAY order the option codes in the
128 PRL by option code number (lowest to highest).
129*/
130/* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */
131static const uint8_t default_req_opts_anonymize[] = {
75924885
YW
132 SD_DHCP_OPTION_SUBNET_MASK, /* 1 */
133 SD_DHCP_OPTION_ROUTER, /* 3 */
134 SD_DHCP_OPTION_DOMAIN_NAME_SERVER, /* 6 */
135 SD_DHCP_OPTION_DOMAIN_NAME, /* 15 */
136 SD_DHCP_OPTION_ROUTER_DISCOVER, /* 31 */
137 SD_DHCP_OPTION_STATIC_ROUTE, /* 33 */
138 SD_DHCP_OPTION_VENDOR_SPECIFIC, /* 43 */
139 SD_DHCP_OPTION_NETBIOS_NAMESERVER, /* 44 */
140 SD_DHCP_OPTION_NETBIOS_NODETYPE, /* 46 */
141 SD_DHCP_OPTION_NETBIOS_SCOPE, /* 47 */
142 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, /* 121 */
143 SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, /* 249 */
144 SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, /* 252 */
db3d2358 145};
146
4b558378
ZJS
147static int client_receive_message_raw(
148 sd_event_source *s,
149 int fd,
150 uint32_t revents,
151 void *userdata);
152static int client_receive_message_udp(
153 sd_event_source *s,
154 int fd,
155 uint32_t revents,
156 void *userdata);
574cc928 157static void client_stop(sd_dhcp_client *client, int error);
aba26854 158
4b558378
ZJS
159int sd_dhcp_client_set_callback(
160 sd_dhcp_client *client,
161 sd_dhcp_client_callback_t cb,
162 void *userdata) {
45aa74c7 163
751246ee
PF
164 assert_return(client, -EINVAL);
165
45aa74c7 166 client->callback = cb;
751246ee
PF
167 client->userdata = userdata;
168
169 return 0;
170}
171
f5de5b00
TG
172int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
173 assert_return(client, -EINVAL);
174
175 client->request_broadcast = !!broadcast;
176
177 return 0;
178}
179
5ee482df 180int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
011feef8
PF
181 size_t i;
182
183 assert_return(client, -EINVAL);
a1140666 184 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
011feef8
PF
185
186 switch(option) {
a1140666 187
22805d92
BG
188 case SD_DHCP_OPTION_PAD:
189 case SD_DHCP_OPTION_OVERLOAD:
190 case SD_DHCP_OPTION_MESSAGE_TYPE:
191 case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
192 case SD_DHCP_OPTION_END:
011feef8
PF
193 return -EINVAL;
194
195 default:
196 break;
197 }
198
199 for (i = 0; i < client->req_opts_size; i++)
200 if (client->req_opts[i] == option)
201 return -EEXIST;
202
7a7c74ca 203 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
011feef8
PF
204 client->req_opts_size + 1))
205 return -ENOMEM;
206
7a7c74ca 207 client->req_opts[client->req_opts_size++] = option;
011feef8
PF
208
209 return 0;
210}
211
4b558378
ZJS
212int sd_dhcp_client_set_request_address(
213 sd_dhcp_client *client,
214 const struct in_addr *last_addr) {
a1140666 215
011feef8 216 assert_return(client, -EINVAL);
a1140666 217 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
011feef8
PF
218
219 if (last_addr)
220 client->last_addr = last_addr->s_addr;
221 else
222 client->last_addr = INADDR_ANY;
223
224 return 0;
225}
226
2f8e7633 227int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
011feef8 228
2f8e7633
LP
229 assert_return(client, -EINVAL);
230 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
231 assert_return(ifindex > 0, -EINVAL);
011feef8 232
2f8e7633 233 client->ifindex = ifindex;
011feef8
PF
234 return 0;
235}
236
4b558378
ZJS
237int sd_dhcp_client_set_mac(
238 sd_dhcp_client *client,
239 const uint8_t *addr,
240 size_t addr_len,
241 uint16_t arp_type) {
242
574cc928 243 DHCP_CLIENT_DONT_DESTROY(client);
4644fee0
TG
244 bool need_restart = false;
245
46a66b79 246 assert_return(client, -EINVAL);
4644fee0 247 assert_return(addr, -EINVAL);
76253e73
DW
248 assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
249 assert_return(arp_type > 0, -EINVAL);
250
251 if (arp_type == ARPHRD_ETHER)
252 assert_return(addr_len == ETH_ALEN, -EINVAL);
253 else if (arp_type == ARPHRD_INFINIBAND)
254 assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
255 else
256 return -EINVAL;
46a66b79 257
76253e73
DW
258 if (client->mac_addr_len == addr_len &&
259 memcmp(&client->mac_addr, addr, addr_len) == 0)
4644fee0
TG
260 return 0;
261
781ca7a1 262 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
a1140666 263 log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting");
4644fee0 264 need_restart = true;
03748142 265 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
4644fee0 266 }
02ec5cd7 267
76253e73
DW
268 memcpy(&client->mac_addr, addr, addr_len);
269 client->mac_addr_len = addr_len;
270 client->arp_type = arp_type;
271
ba6c0fd6
DW
272 if (need_restart && client->state != DHCP_STATE_STOPPED)
273 sd_dhcp_client_start(client);
274
275 return 0;
276}
277
4b558378
ZJS
278int sd_dhcp_client_get_client_id(
279 sd_dhcp_client *client,
280 uint8_t *type,
281 const uint8_t **data,
282 size_t *data_len) {
ba6c0fd6
DW
283
284 assert_return(client, -EINVAL);
285 assert_return(type, -EINVAL);
286 assert_return(data, -EINVAL);
287 assert_return(data_len, -EINVAL);
288
289 *type = 0;
290 *data = NULL;
291 *data_len = 0;
292 if (client->client_id_len) {
5bac5235 293 *type = client->client_id.type;
ba6c0fd6 294 *data = client->client_id.raw.data;
5bac5235 295 *data_len = client->client_id_len - sizeof(client->client_id.type);
ba6c0fd6
DW
296 }
297
298 return 0;
299}
300
4b558378
ZJS
301int sd_dhcp_client_set_client_id(
302 sd_dhcp_client *client,
303 uint8_t type,
304 const uint8_t *data,
305 size_t data_len) {
306
ba6c0fd6
DW
307 DHCP_CLIENT_DONT_DESTROY(client);
308 bool need_restart = false;
309
310 assert_return(client, -EINVAL);
311 assert_return(data, -EINVAL);
312 assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
313
5bac5235
TG
314 if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
315 client->client_id.type == type &&
ba6c0fd6
DW
316 memcmp(&client->client_id.raw.data, data, data_len) == 0)
317 return 0;
318
bfda0d0f
TH
319 /* For hardware types, log debug message about unexpected data length.
320 *
321 * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only
322 * last last 8 bytes of the address are stable and suitable to put into
323 * the client-id. The caller is advised to account for that. */
324 if ((type == ARPHRD_ETHER && data_len != ETH_ALEN) ||
325 (type == ARPHRD_INFINIBAND && data_len != 8))
326 log_dhcp_client(client, "Changing client ID to hardware type %u with "
327 "unexpected address length %zu",
328 type, data_len);
329
ba6c0fd6
DW
330 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
331 log_dhcp_client(client, "Changing client ID on running DHCP "
332 "client, restarting");
333 need_restart = true;
03748142 334 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
ba6c0fd6
DW
335 }
336
5bac5235 337 client->client_id.type = type;
ba6c0fd6 338 memcpy(&client->client_id.raw.data, data, data_len);
5bac5235 339 client->client_id_len = data_len + sizeof (client->client_id.type);
46a66b79 340
781ca7a1 341 if (need_restart && client->state != DHCP_STATE_STOPPED)
4644fee0
TG
342 sd_dhcp_client_start(client);
343
46a66b79
PF
344 return 0;
345}
346
d7df2fd3
ZJS
347/**
348 * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
349 * without further modification. Otherwise, if duid_type is supported, DUID
350 * is set based on that type. Otherwise, an error is returned.
351 */
7e90a499 352static int dhcp_client_set_iaid_duid_internal(
4b558378 353 sd_dhcp_client *client,
8217ed5e
TH
354 bool iaid_append,
355 bool iaid_set,
4b558378
ZJS
356 uint32_t iaid,
357 uint16_t duid_type,
f7a92d1a 358 const void *duid,
7e90a499
YW
359 size_t duid_len,
360 usec_t llt_time) {
4b558378 361
413708d1
VK
362 DHCP_CLIENT_DONT_DESTROY(client);
363 int r;
d7df2fd3
ZJS
364 size_t len;
365
413708d1 366 assert_return(client, -EINVAL);
da3c49e9 367 assert_return(duid_len == 0 || duid, -EINVAL);
d7df2fd3 368
da3c49e9 369 if (duid) {
ab4a88bc 370 r = dhcp_validate_duid_len(duid_type, duid_len, true);
d7df2fd3
ZJS
371 if (r < 0)
372 return r;
373 }
413708d1 374
d7df2fd3 375 zero(client->client_id);
413708d1
VK
376 client->client_id.type = 255;
377
8217ed5e
TH
378 if (iaid_append) {
379 if (iaid_set)
380 client->client_id.ns.iaid = htobe32(iaid);
381 else {
dace710c
YW
382 r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
383 client->mac_addr_len,
6d13616b 384 true,
dace710c
YW
385 &client->client_id.ns.iaid);
386 if (r < 0)
387 return r;
8217ed5e 388 }
dace710c 389 }
413708d1 390
da3c49e9 391 if (duid) {
413708d1
VK
392 client->client_id.ns.duid.type = htobe16(duid_type);
393 memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len);
d7df2fd3 394 len = sizeof(client->client_id.ns.duid.type) + duid_len;
d7df2fd3 395 } else
27eba50e 396 switch (duid_type) {
335f80a6 397 case DUID_TYPE_LLT:
339697f0 398 if (client->mac_addr_len == 0)
335f80a6
YW
399 return -EOPNOTSUPP;
400
7e90a499 401 r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
335f80a6
YW
402 if (r < 0)
403 return r;
404 break;
27eba50e
YW
405 case DUID_TYPE_EN:
406 r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
407 if (r < 0)
408 return r;
409 break;
335f80a6 410 case DUID_TYPE_LL:
339697f0 411 if (client->mac_addr_len == 0)
335f80a6
YW
412 return -EOPNOTSUPP;
413
414 r = dhcp_identifier_set_duid_ll(&client->client_id.ns.duid, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
415 if (r < 0)
416 return r;
417 break;
27eba50e
YW
418 case DUID_TYPE_UUID:
419 r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len);
420 if (r < 0)
421 return r;
422 break;
423 default:
335f80a6 424 return -EINVAL;
27eba50e 425 }
413708d1 426
d7df2fd3 427 client->client_id_len = sizeof(client->client_id.type) + len +
8217ed5e 428 (iaid_append ? sizeof(client->client_id.ns.iaid) : 0);
413708d1
VK
429
430 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
8217ed5e 431 log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : "");
413708d1
VK
432 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
433 sd_dhcp_client_start(client);
434 }
435
436 return 0;
437}
438
dace710c
YW
439int sd_dhcp_client_set_iaid_duid(
440 sd_dhcp_client *client,
8217ed5e 441 bool iaid_set,
dace710c
YW
442 uint32_t iaid,
443 uint16_t duid_type,
444 const void *duid,
445 size_t duid_len) {
8217ed5e 446 return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, duid_type, duid, duid_len, 0);
7e90a499
YW
447}
448
449int sd_dhcp_client_set_iaid_duid_llt(
450 sd_dhcp_client *client,
8217ed5e 451 bool iaid_set,
7e90a499
YW
452 uint32_t iaid,
453 usec_t llt_time) {
8217ed5e 454 return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, DUID_TYPE_LLT, NULL, 0, llt_time);
dace710c
YW
455}
456
457int sd_dhcp_client_set_duid(
458 sd_dhcp_client *client,
459 uint16_t duid_type,
460 const void *duid,
461 size_t duid_len) {
8217ed5e 462 return dhcp_client_set_iaid_duid_internal(client, false, false, 0, duid_type, duid, duid_len, 0);
7e90a499
YW
463}
464
465int sd_dhcp_client_set_duid_llt(
466 sd_dhcp_client *client,
467 usec_t llt_time) {
8217ed5e 468 return dhcp_client_set_iaid_duid_internal(client, false, false, 0, DUID_TYPE_LLT, NULL, 0, llt_time);
dace710c
YW
469}
470
4b558378
ZJS
471int sd_dhcp_client_set_hostname(
472 sd_dhcp_client *client,
473 const char *hostname) {
474
4cc7a82c
EY
475 assert_return(client, -EINVAL);
476
9740eae6 477 /* Make sure hostnames qualify as DNS and as Linux hostnames */
ef8b0084 478 if (hostname &&
9740eae6 479 !(hostname_is_valid(hostname, false) && dns_name_is_valid(hostname) > 0))
23873e25
BG
480 return -EINVAL;
481
ef8b0084 482 return free_and_strdup(&client->hostname, hostname);
4cc7a82c
EY
483}
484
4b558378
ZJS
485int sd_dhcp_client_set_vendor_class_identifier(
486 sd_dhcp_client *client,
487 const char *vci) {
488
edb85f0d
SS
489 assert_return(client, -EINVAL);
490
ef8b0084 491 return free_and_strdup(&client->vendor_class_identifier, vci);
edb85f0d
SS
492}
493
af1c0de0
SS
494int sd_dhcp_client_set_user_class(
495 sd_dhcp_client *client,
496 const char* const* user_class) {
497
498 _cleanup_strv_free_ char **s = NULL;
499 char **p;
500
501 STRV_FOREACH(p, (char **) user_class)
502 if (strlen(*p) > 255)
503 return -ENAMETOOLONG;
504
505 s = strv_copy((char **) user_class);
506 if (!s)
507 return -ENOMEM;
508
509 client->user_class = TAKE_PTR(s);
510
511 return 0;
512}
513
9faed222
SS
514int sd_dhcp_client_set_client_port(
515 sd_dhcp_client *client,
516 uint16_t port) {
517
518 assert_return(client, -EINVAL);
519
520 client->port = port;
521
522 return 0;
523}
524
324f8187
TG
525int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
526 assert_return(client, -EINVAL);
527 assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
528
529 client->mtu = mtu;
530
531 return 0;
532}
533
715cedfb
SS
534int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) {
535 assert_return(client, -EINVAL);
536
537 client->max_attempts = max_attempts;
538
539 return 0;
540}
541
cb29c156
SS
542static sd_dhcp_option* dhcp_option_free(sd_dhcp_option *i) {
543 if (!i)
544 return NULL;
545
546 free(i->data);
547 return mfree(i);
548}
549
550int sd_dhcp_option_new(uint8_t option, void *data, size_t length, sd_dhcp_option **ret) {
cb29c156
SS
551 assert(ret);
552
9b08c804 553 _cleanup_free_ void *q = memdup(data, length);
cb29c156
SS
554 if (!q)
555 return -ENOMEM;
556
9b08c804 557 sd_dhcp_option *p = new(sd_dhcp_option, 1);
cb29c156
SS
558 if (!p)
559 return -ENOMEM;
560
561 *p = (sd_dhcp_option) {
562 .n_ref = 1,
563 .option = option,
564 .length = length,
565 .data = TAKE_PTR(q),
566 };
567
568 *ret = TAKE_PTR(p);
569 return 0;
570}
571
572DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_option, sd_dhcp_option, dhcp_option_free);
573DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
574 dhcp_option_hash_ops,
575 void,
576 trivial_hash_func,
577 trivial_compare_func,
578 sd_dhcp_option,
579 sd_dhcp_option_unref);
580
581int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) {
582 int r;
583
584 assert_return(client, -EINVAL);
585 assert_return(v, -EINVAL);
586
587 r = ordered_hashmap_ensure_allocated(&client->options, &dhcp_option_hash_ops);
588 if (r < 0)
589 return r;
590
591 r = ordered_hashmap_put(client->options, UINT_TO_PTR(v->option), v);
592 if (r < 0)
593 return r;
594
595 sd_dhcp_option_ref(v);
596 return 0;
597}
598
a6cc569e 599int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
751246ee 600 assert_return(client, -EINVAL);
751246ee 601
727b5734 602 if (!IN_SET(client->state, DHCP_STATE_SELECTING, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING))
a6cc569e 603 return -EADDRNOTAVAIL;
751246ee 604
a1140666
LP
605 if (ret)
606 *ret = client->lease;
4f882b2a
TG
607
608 return 0;
609}
610
afe42aef
SC
611int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
612 assert_return(client, -EINVAL);
613
614 client->ip_service_type = type;
615
616 return 0;
617}
618
727b5734 619static int client_notify(sd_dhcp_client *client, int event) {
45aa74c7
LP
620 assert(client);
621
622 if (client->callback)
727b5734
SS
623 return client->callback(client, event, client->userdata);
624
625 return 0;
3e3d8f78
PF
626}
627
0f941add 628static int client_initialize(sd_dhcp_client *client) {
bbdf06d9 629 assert_return(client, -EINVAL);
bbdf06d9 630
a1140666 631 client->receive_message = sd_event_source_unref(client->receive_message);
8c00042c 632
22fc2420 633 client->fd = asynchronous_close(client->fd);
8c00042c 634
a3fa4287
YW
635 (void) event_source_disable(client->timeout_resend);
636 (void) event_source_disable(client->timeout_t1);
637 (void) event_source_disable(client->timeout_t2);
638 (void) event_source_disable(client->timeout_expire);
51debc1e 639
11793fcd 640 client->attempt = 0;
e2dfc79f 641
f8fdefe4 642 client->state = DHCP_STATE_INIT;
0f941add 643 client->xid = 0;
bbdf06d9 644
0339cd77 645 client->lease = sd_dhcp_lease_unref(client->lease);
8c00042c 646
0f941add
PF
647 return 0;
648}
649
574cc928
TG
650static void client_stop(sd_dhcp_client *client, int error) {
651 assert(client);
0f941add 652
ccfdc9a1 653 if (error < 0)
7fa6223f 654 log_dhcp_client_errno(client, error, "STOPPED: %m");
03748142 655 else if (error == SD_DHCP_CLIENT_EVENT_STOP)
2d2349cc
TG
656 log_dhcp_client(client, "STOPPED");
657 else
658 log_dhcp_client(client, "STOPPED: Unknown event");
0f941add 659
574cc928 660 client_notify(client, error);
ee57a737 661
574cc928 662 client_initialize(client);
bbdf06d9
PF
663}
664
4b558378
ZJS
665static int client_message_init(
666 sd_dhcp_client *client,
667 DHCPPacket **ret,
668 uint8_t type,
669 size_t *_optlen,
670 size_t *_optoffset) {
671
3587161a 672 _cleanup_free_ DHCPPacket *packet = NULL;
424a8732 673 size_t optlen, optoffset, size;
8a9e7616 674 be16_t max_size;
d8d74ef0
DW
675 usec_t time_now;
676 uint16_t secs;
cf597f65 677 int r;
46a66b79 678
6236f49b 679 assert(client);
d8d74ef0 680 assert(client->start_time);
424a8732
TG
681 assert(ret);
682 assert(_optlen);
683 assert(_optoffset);
1501b429 684 assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE));
0a1b6da8 685
424a8732
TG
686 optlen = DHCP_MIN_OPTIONS_SIZE;
687 size = sizeof(DHCPPacket) + optlen;
688
689 packet = malloc0(size);
690 if (!packet)
691 return -ENOMEM;
692
693 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
76253e73 694 client->arp_type, optlen, &optoffset);
cf597f65
TG
695 if (r < 0)
696 return r;
46a66b79 697
0a1b6da8
TG
698 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
699 refuse to issue an DHCP lease if 'secs' is set to zero */
d8d74ef0
DW
700 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
701 if (r < 0)
702 return r;
703 assert(time_now >= client->start_time);
704
705 /* seconds between sending first and last DISCOVER
706 * must always be strictly positive to deal with broken servers */
707 secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
708 packet->dhcp.secs = htobe16(secs);
0a1b6da8 709
63a07041
CA
710 /* RFC2132 section 4.1
711 A client that cannot receive unicast IP datagrams until its protocol
712 software has been configured with an IP address SHOULD set the
713 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
714 DHCPREQUEST messages that client sends. The BROADCAST bit will
715 provide a hint to the DHCP server and BOOTP relay agent to broadcast
f5de5b00
TG
716 any messages to the client on the client's subnet.
717
718 Note: some interfaces needs this to be enabled, but some networks
719 needs this to be disabled as broadcasts are filteretd, so this
720 needs to be configurable */
76253e73 721 if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
f5de5b00 722 packet->dhcp.flags = htobe16(0x8000);
63a07041 723
50d6810e
TG
724 /* RFC2132 section 4.1.1:
725 The client MUST include its hardware address in the ’chaddr’ field, if
76253e73
DW
726 necessary for delivery of DHCP reply messages. Non-Ethernet
727 interfaces will leave 'chaddr' empty and use the client identifier
728 instead (eg, RFC 4390 section 2.1).
50d6810e 729 */
76253e73
DW
730 if (client->arp_type == ARPHRD_ETHER)
731 memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
f5a70de7 732
afec4539 733 /* If no client identifier exists, construct an RFC 4361-compliant one */
5bac5235
TG
734 if (client->client_id_len == 0) {
735 size_t duid_len;
736
737 client->client_id.type = 255;
738
6d13616b
TH
739 r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
740 true, &client->client_id.ns.iaid);
5bac5235
TG
741 if (r < 0)
742 return r;
743
744 r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len);
745 if (r < 0)
746 return r;
747
748 client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
ba6c0fd6
DW
749 }
750
ee57a737 751 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
46a66b79 752 Identifier option is not set */
ba6c0fd6
DW
753 if (client->client_id_len) {
754 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
22805d92 755 SD_DHCP_OPTION_CLIENT_IDENTIFIER,
ba6c0fd6 756 client->client_id_len,
5bac5235 757 &client->client_id);
ba6c0fd6
DW
758 if (r < 0)
759 return r;
760 }
50d6810e
TG
761
762 /* RFC2131 section 3.5:
763 in its initial DHCPDISCOVER or DHCPREQUEST message, a
764 client may provide the server with a list of specific
765 parameters the client is interested in. If the client
766 includes a list of parameters in a DHCPDISCOVER message,
767 it MUST include that list in any subsequent DHCPREQUEST
768 messages.
769 */
5e77a146 770
771 /* RFC7844 section 3:
772 MAY contain the Parameter Request List option. */
773 /* NOTE: in case that there would be an option to do not send
774 * any PRL at all, the size should be checked before sending */
1501b429 775 if (client->req_opts_size > 0 && type != DHCP_RELEASE) {
5e77a146 776 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
777 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
778 client->req_opts_size, client->req_opts);
779 if (r < 0)
780 return r;
781 }
8a9e7616 782
50d6810e
TG
783 /* RFC2131 section 3.5:
784 The client SHOULD include the ’maximum DHCP message size’ option to
785 let the server know how large the server may make its DHCP messages.
786
787 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
f21f31b2 788 than the defined default size unless the Maximum Message Size option
f131770b 789 is explicitly set
324f8187
TG
790
791 RFC3442 "Requirements to Avoid Sizing Constraints":
792 Because a full routing table can be quite large, the standard 576
793 octet maximum size for a DHCP message may be too short to contain
794 some legitimate Classless Static Route options. Because of this,
795 clients implementing the Classless Static Route option SHOULD send a
796 Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
797 stack is capable of receiving larger IP datagrams. In this case, the
798 client SHOULD set the value of this option to at least the MTU of the
799 interface that the client is configuring. The client MAY set the
800 value of this option higher, up to the size of the largest UDP packet
801 it is prepared to accept. (Note that the value specified in the
802 Maximum DHCP Message Size option is the total maximum packet size,
803 including IP and UDP headers.)
50d6810e 804 */
1b41b815 805 /* RFC7844 section 3:
806 SHOULD NOT contain any other option. */
1501b429 807 if (!client->anonymize && type != DHCP_RELEASE) {
1b41b815 808 max_size = htobe16(size);
809 r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
810 SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
811 2, &max_size);
812 if (r < 0)
813 return r;
814 }
46a66b79 815
424a8732
TG
816 *_optlen = optlen;
817 *_optoffset = optoffset;
1cc6c93a 818 *ret = TAKE_PTR(packet);
424a8732 819
46a66b79
PF
820 return 0;
821}
822
4b558378
ZJS
823static int client_append_fqdn_option(
824 DHCPMessage *message,
825 size_t optlen,
826 size_t *optoffset,
827 const char *fqdn) {
828
23873e25
BG
829 uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
830 int r;
831
832 buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
833 DHCP_FQDN_FLAG_E; /* Canonical wire format */
834 buffer[1] = 0; /* RCODE1 (deprecated) */
835 buffer[2] = 0; /* RCODE2 (deprecated) */
836
3cd03457 837 r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false);
23873e25
BG
838 if (r > 0)
839 r = dhcp_option_append(message, optlen, optoffset, 0,
22805d92 840 SD_DHCP_OPTION_FQDN, 3 + r, buffer);
23873e25
BG
841
842 return r;
843}
844
4b558378
ZJS
845static int dhcp_client_send_raw(
846 sd_dhcp_client *client,
847 DHCPPacket *packet,
848 size_t len) {
849
9faed222 850 dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
afe42aef 851 INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type);
63edaa62
TG
852
853 return dhcp_network_send_raw_socket(client->fd, &client->link,
854 packet, len);
855}
856
6236f49b 857static int client_send_discover(sd_dhcp_client *client) {
9f2a50a3 858 _cleanup_free_ DHCPPacket *discover = NULL;
424a8732 859 size_t optoffset, optlen;
cb29c156
SS
860 sd_dhcp_option *j;
861 Iterator i;
6236f49b
TG
862 int r;
863
864 assert(client);
4c701096 865 assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
50d6810e 866
424a8732
TG
867 r = client_message_init(client, &discover, DHCP_DISCOVER,
868 &optlen, &optoffset);
6236f49b
TG
869 if (r < 0)
870 return r;
46a66b79 871
50d6810e
TG
872 /* the client may suggest values for the network address
873 and lease time in the DHCPDISCOVER message. The client may include
874 the ’requested IP address’ option to suggest that a particular IP
875 address be assigned, and may include the ’IP address lease time’
876 option to suggest the lease time it would like.
877 */
46a66b79 878 if (client->last_addr != INADDR_ANY) {
04b28be1 879 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 880 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
20b958bf 881 4, &client->last_addr);
6236f49b
TG
882 if (r < 0)
883 return r;
46a66b79
PF
884 }
885
4cc7a82c 886 if (client->hostname) {
23873e25
BG
887 /* According to RFC 4702 "clients that send the Client FQDN option in
888 their messages MUST NOT also send the Host Name option". Just send
889 one of the two depending on the hostname type.
890 */
dc477e73 891 if (dns_name_is_single_label(client->hostname)) {
23873e25
BG
892 /* it is unclear from RFC 2131 if client should send hostname in
893 DHCPDISCOVER but dhclient does and so we do as well
894 */
895 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 896 SD_DHCP_OPTION_HOST_NAME,
23873e25
BG
897 strlen(client->hostname), client->hostname);
898 } else
899 r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
900 client->hostname);
4cc7a82c
EY
901 if (r < 0)
902 return r;
903 }
904
edb85f0d
SS
905 if (client->vendor_class_identifier) {
906 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 907 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
edb85f0d
SS
908 strlen(client->vendor_class_identifier),
909 client->vendor_class_identifier);
910 if (r < 0)
911 return r;
912 }
913
af1c0de0
SS
914 if (client->user_class) {
915 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
916 SD_DHCP_OPTION_USER_CLASS,
917 strv_length(client->user_class),
918 client->user_class);
919 if (r < 0)
920 return r;
921 }
922
cb29c156
SS
923 ORDERED_HASHMAP_FOREACH(j, client->options, i) {
924 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
925 j->option, j->length, j->data);
926 if (r < 0)
927 return r;
928 }
929
04b28be1 930 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 931 SD_DHCP_OPTION_END, 0, NULL);
f7926298
TA
932 if (r < 0)
933 return r;
46a66b79 934
50d6810e
TG
935 /* We currently ignore:
936 The client SHOULD wait a random time between one and ten seconds to
937 desynchronize the use of DHCP at startup.
938 */
20b958bf 939 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
6236f49b
TG
940 if (r < 0)
941 return r;
e2dfc79f 942
ee57a737
TG
943 log_dhcp_client(client, "DISCOVER");
944
63edaa62 945 return 0;
e2dfc79f
PF
946}
947
6236f49b 948static int client_send_request(sd_dhcp_client *client) {
8186d9dd 949 _cleanup_free_ DHCPPacket *request = NULL;
424a8732 950 size_t optoffset, optlen;
6236f49b 951 int r;
e2dfc79f 952
a1140666
LP
953 assert(client);
954
955 r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset);
6236f49b
TG
956 if (r < 0)
957 return r;
46a66b79 958
8b1243f7 959 switch (client->state) {
50d6810e
TG
960 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
961 SELECTING should be REQUESTING)
962 */
963
964 case DHCP_STATE_REQUESTING:
965 /* Client inserts the address of the selected server in ’server
966 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
967 filled in with the yiaddr value from the chosen DHCPOFFER.
968 */
8b1243f7 969
04b28be1 970 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 971 SD_DHCP_OPTION_SERVER_IDENTIFIER,
50d6810e 972 4, &client->lease->server_address);
6236f49b
TG
973 if (r < 0)
974 return r;
8b1243f7 975
04b28be1 976 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 977 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
6236f49b
TG
978 4, &client->lease->address);
979 if (r < 0)
980 return r;
981
50d6810e
TG
982 break;
983
984 case DHCP_STATE_INIT_REBOOT:
985 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
986 option MUST be filled in with client’s notion of its previously
987 assigned address. ’ciaddr’ MUST be zero.
988 */
04b28be1 989 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 990 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
50d6810e 991 4, &client->last_addr);
6236f49b
TG
992 if (r < 0)
993 return r;
8b1243f7
PF
994 break;
995
8b1243f7 996 case DHCP_STATE_RENEWING:
50d6810e
TG
997 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
998 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
999 client’s IP address.
1000 */
1001
8b1243f7 1002 case DHCP_STATE_REBINDING:
50d6810e
TG
1003 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1004 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
1005 client’s IP address.
1006
1007 This message MUST be broadcast to the 0xffffffff IP broadcast address.
1008 */
1009 request->dhcp.ciaddr = client->lease->address;
8b1243f7
PF
1010
1011 break;
781ca7a1 1012
50d6810e
TG
1013 case DHCP_STATE_INIT:
1014 case DHCP_STATE_SELECTING:
1015 case DHCP_STATE_REBOOTING:
1016 case DHCP_STATE_BOUND:
781ca7a1
PF
1017 case DHCP_STATE_STOPPED:
1018 return -EINVAL;
e2dfc79f 1019 }
46a66b79 1020
4cc7a82c 1021 if (client->hostname) {
dc477e73 1022 if (dns_name_is_single_label(client->hostname))
23873e25 1023 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 1024 SD_DHCP_OPTION_HOST_NAME,
23873e25
BG
1025 strlen(client->hostname), client->hostname);
1026 else
1027 r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
1028 client->hostname);
4cc7a82c
EY
1029 if (r < 0)
1030 return r;
1031 }
1032
5153494f
AG
1033 if (client->vendor_class_identifier) {
1034 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
1035 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
1036 strlen(client->vendor_class_identifier),
1037 client->vendor_class_identifier);
1038 if (r < 0)
1039 return r;
1040 }
1041
04b28be1 1042 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 1043 SD_DHCP_OPTION_END, 0, NULL);
6236f49b
TG
1044 if (r < 0)
1045 return r;
46a66b79 1046
bdbb98d9 1047 if (client->state == DHCP_STATE_RENEWING)
6236f49b
TG
1048 r = dhcp_network_send_udp_socket(client->fd,
1049 client->lease->server_address,
1050 DHCP_PORT_SERVER,
1051 &request->dhcp,
20b958bf 1052 sizeof(DHCPMessage) + optoffset);
bdbb98d9 1053 else
20b958bf 1054 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
6236f49b
TG
1055 if (r < 0)
1056 return r;
46a66b79 1057
998d8047 1058 switch (client->state) {
a1140666 1059
998d8047
TG
1060 case DHCP_STATE_REQUESTING:
1061 log_dhcp_client(client, "REQUEST (requesting)");
1062 break;
a1140666 1063
998d8047
TG
1064 case DHCP_STATE_INIT_REBOOT:
1065 log_dhcp_client(client, "REQUEST (init-reboot)");
1066 break;
a1140666 1067
998d8047
TG
1068 case DHCP_STATE_RENEWING:
1069 log_dhcp_client(client, "REQUEST (renewing)");
1070 break;
a1140666 1071
998d8047
TG
1072 case DHCP_STATE_REBINDING:
1073 log_dhcp_client(client, "REQUEST (rebinding)");
1074 break;
a1140666 1075
998d8047
TG
1076 default:
1077 log_dhcp_client(client, "REQUEST (invalid)");
1078 break;
1079 }
ee57a737 1080
63edaa62 1081 return 0;
46a66b79
PF
1082}
1083
7739a40b
TG
1084static int client_start(sd_dhcp_client *client);
1085
4b558378
ZJS
1086static int client_timeout_resend(
1087 sd_event_source *s,
1088 uint64_t usec,
1089 void *userdata) {
1090
d3d8ac2f 1091 sd_dhcp_client *client = userdata;
574cc928 1092 DHCP_CLIENT_DONT_DESTROY(client);
aba26854 1093 usec_t next_timeout = 0;
d23c45bf 1094 uint64_t time_now;
aba26854 1095 uint32_t time_left;
d23c45bf 1096 int r;
b25ef18b
TG
1097
1098 assert(s);
1099 assert(client);
1100 assert(client->event);
d3d8ac2f 1101
fa94c34b 1102 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
d23c45bf
TG
1103 if (r < 0)
1104 goto error;
1105
aba26854 1106 switch (client->state) {
a1140666 1107
aba26854
PF
1108 case DHCP_STATE_RENEWING:
1109
e5002702 1110 time_left = (client->lease->t2 - client->lease->t1) / 2;
aba26854
PF
1111 if (time_left < 60)
1112 time_left = 60;
d3d8ac2f 1113
d23c45bf 1114 next_timeout = time_now + time_left * USEC_PER_SEC;
d3d8ac2f 1115
aba26854
PF
1116 break;
1117
3dd71400
PF
1118 case DHCP_STATE_REBINDING:
1119
e5002702 1120 time_left = (client->lease->lifetime - client->lease->t2) / 2;
3dd71400
PF
1121 if (time_left < 60)
1122 time_left = 60;
1123
d23c45bf 1124 next_timeout = time_now + time_left * USEC_PER_SEC;
3dd71400
PF
1125 break;
1126
8b1243f7
PF
1127 case DHCP_STATE_REBOOTING:
1128 /* start over as we did not receive a timely ack or nak */
7739a40b 1129 r = client_initialize(client);
eb105b96
TG
1130 if (r < 0)
1131 goto error;
8b1243f7 1132
998d8047
TG
1133 r = client_start(client);
1134 if (r < 0)
1135 goto error;
1136 else {
1137 log_dhcp_client(client, "REBOOTED");
1138 return 0;
1139 }
7739a40b 1140
aba26854
PF
1141 case DHCP_STATE_INIT:
1142 case DHCP_STATE_INIT_REBOOT:
aba26854
PF
1143 case DHCP_STATE_SELECTING:
1144 case DHCP_STATE_REQUESTING:
1145 case DHCP_STATE_BOUND:
aba26854 1146
715cedfb 1147 if (client->attempt < client->max_attempts)
11793fcd 1148 client->attempt++;
8bc17bb3
SS
1149 else
1150 goto error;
aba26854 1151
715cedfb 1152 next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
aba26854
PF
1153
1154 break;
781ca7a1
PF
1155
1156 case DHCP_STATE_STOPPED:
1157 r = -EINVAL;
1158 goto error;
aba26854
PF
1159 }
1160
9bf3b535 1161 next_timeout += (random_u32() & 0x1fffff);
d3d8ac2f 1162
a3fa4287
YW
1163 r = event_reset_time(client->event, &client->timeout_resend,
1164 clock_boottime_or_monotonic(),
1165 next_timeout, 10 * USEC_PER_MSEC,
1166 client_timeout_resend, client,
1167 client->event_priority, "dhcp4-resend-timer", true);
9021bb9f
TG
1168 if (r < 0)
1169 goto error;
1170
e2dfc79f
PF
1171 switch (client->state) {
1172 case DHCP_STATE_INIT:
6236f49b 1173 r = client_send_discover(client);
b25ef18b 1174 if (r >= 0) {
e2dfc79f 1175 client->state = DHCP_STATE_SELECTING;
11793fcd 1176 client->attempt = 0;
715cedfb
SS
1177 } else if (client->attempt >= client->max_attempts)
1178 goto error;
e2dfc79f
PF
1179
1180 break;
1181
1182 case DHCP_STATE_SELECTING:
6236f49b 1183 r = client_send_discover(client);
715cedfb 1184 if (r < 0 && client->attempt >= client->max_attempts)
d3d8ac2f
PF
1185 goto error;
1186
e2dfc79f
PF
1187 break;
1188
8b1243f7 1189 case DHCP_STATE_INIT_REBOOT:
e2dfc79f 1190 case DHCP_STATE_REQUESTING:
aba26854 1191 case DHCP_STATE_RENEWING:
3dd71400 1192 case DHCP_STATE_REBINDING:
6236f49b 1193 r = client_send_request(client);
715cedfb 1194 if (r < 0 && client->attempt >= client->max_attempts)
e2dfc79f 1195 goto error;
d3d8ac2f 1196
8b1243f7
PF
1197 if (client->state == DHCP_STATE_INIT_REBOOT)
1198 client->state = DHCP_STATE_REBOOTING;
1199
d23c45bf 1200 client->request_sent = time_now;
51debc1e 1201
d3d8ac2f
PF
1202 break;
1203
d3d8ac2f 1204 case DHCP_STATE_REBOOTING:
d3d8ac2f 1205 case DHCP_STATE_BOUND:
d3d8ac2f
PF
1206
1207 break;
781ca7a1
PF
1208
1209 case DHCP_STATE_STOPPED:
1210 r = -EINVAL;
1211 goto error;
d3d8ac2f
PF
1212 }
1213
1214 return 0;
1215
1216error:
b25ef18b 1217 client_stop(client, r);
d3d8ac2f
PF
1218
1219 /* Errors were dealt with when stopping the client, don't spill
1220 errors into the event loop handler */
1221 return 0;
1222}
1223
4b558378
ZJS
1224static int client_initialize_io_events(
1225 sd_dhcp_client *client,
1226 sd_event_io_handler_t io_callback) {
1227
6a1cd41e
PF
1228 int r;
1229
b25ef18b
TG
1230 assert(client);
1231 assert(client->event);
1232
151b9b96
LP
1233 r = sd_event_add_io(client->event, &client->receive_message,
1234 client->fd, EPOLLIN, io_callback,
1235 client);
6a1cd41e
PF
1236 if (r < 0)
1237 goto error;
1238
e5002702
TG
1239 r = sd_event_source_set_priority(client->receive_message,
1240 client->event_priority);
b25ef18b
TG
1241 if (r < 0)
1242 goto error;
1243
356779df 1244 r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
9021bb9f
TG
1245 if (r < 0)
1246 goto error;
1247
0af03ba5
TG
1248error:
1249 if (r < 0)
1250 client_stop(client, r);
1251
1252 return 0;
1253}
1254
1255static int client_initialize_time_events(sd_dhcp_client *client) {
1d1a3e0a 1256 uint64_t usec = 0;
0af03ba5
TG
1257 int r;
1258
1259 assert(client);
1260 assert(client->event);
1261
bdbb98d9 1262 if (client->start_delay > 0) {
8ecdcb55 1263 assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
1d1a3e0a
BG
1264 usec += client->start_delay;
1265 }
1266
a3fa4287
YW
1267 r = event_reset_time(client->event, &client->timeout_resend,
1268 clock_boottime_or_monotonic(),
1269 usec, 0,
1270 client_timeout_resend, client,
1271 client->event_priority, "dhcp4-resend-timer", true);
6a1cd41e
PF
1272 if (r < 0)
1273 client_stop(client, r);
1274
1275 return 0;
1276
1277}
1278
4b558378 1279static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) {
0af03ba5
TG
1280 client_initialize_io_events(client, io_callback);
1281 client_initialize_time_events(client);
1282
1283 return 0;
1284}
1285
1d1a3e0a 1286static int client_start_delayed(sd_dhcp_client *client) {
0f941add
PF
1287 int r;
1288
1289 assert_return(client, -EINVAL);
1290 assert_return(client->event, -EINVAL);
2f8e7633 1291 assert_return(client->ifindex > 0, -EINVAL);
0f941add
PF
1292 assert_return(client->fd < 0, -EBUSY);
1293 assert_return(client->xid == 0, -EINVAL);
a1140666 1294 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY);
0f941add
PF
1295
1296 client->xid = random_u32();
1297
2f8e7633 1298 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
76253e73 1299 client->xid, client->mac_addr,
9faed222 1300 client->mac_addr_len, client->arp_type, client->port);
0f941add
PF
1301 if (r < 0) {
1302 client_stop(client, r);
1303 return r;
1304 }
0f941add 1305 client->fd = r;
58ec2d3e 1306
3742095b 1307 if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT))
fa94c34b 1308 client->start_time = now(clock_boottime_or_monotonic());
0f941add 1309
0f941add
PF
1310 return client_initialize_events(client, client_receive_message_raw);
1311}
1312
1d1a3e0a
BG
1313static int client_start(sd_dhcp_client *client) {
1314 client->start_delay = 0;
1315 return client_start_delayed(client);
1316}
1317
4b558378 1318static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) {
751246ee 1319 sd_dhcp_client *client = userdata;
574cc928 1320 DHCP_CLIENT_DONT_DESTROY(client);
751246ee 1321
ee57a737
TG
1322 log_dhcp_client(client, "EXPIRED");
1323
03748142 1324 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
0f941add 1325
781ca7a1 1326 /* lease was lost, start over if not freed or stopped in callback */
574cc928 1327 if (client->state != DHCP_STATE_STOPPED) {
e5b04c8d
PF
1328 client_initialize(client);
1329 client_start(client);
1330 }
751246ee 1331
51debc1e
PF
1332 return 0;
1333}
1334
5ee482df 1335static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
3dd71400 1336 sd_dhcp_client *client = userdata;
574cc928 1337 DHCP_CLIENT_DONT_DESTROY(client);
3dd71400
PF
1338 int r;
1339
a1140666
LP
1340 assert(client);
1341
03e334a1 1342 client->receive_message = sd_event_source_unref(client->receive_message);
22fc2420 1343 client->fd = asynchronous_close(client->fd);
3dd71400
PF
1344
1345 client->state = DHCP_STATE_REBINDING;
11793fcd 1346 client->attempt = 0;
3dd71400 1347
2f8e7633 1348 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
76253e73 1349 client->xid, client->mac_addr,
9faed222
SS
1350 client->mac_addr_len, client->arp_type,
1351 client->port);
3dd71400
PF
1352 if (r < 0) {
1353 client_stop(client, r);
1354 return 0;
1355 }
3dd71400
PF
1356 client->fd = r;
1357
d23c45bf 1358 return client_initialize_events(client, client_receive_message_raw);
51debc1e
PF
1359}
1360
4b558378 1361static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
aba26854 1362 sd_dhcp_client *client = userdata;
574cc928 1363 DHCP_CLIENT_DONT_DESTROY(client);
aba26854
PF
1364
1365 client->state = DHCP_STATE_RENEWING;
11793fcd 1366 client->attempt = 0;
aba26854 1367
0af03ba5 1368 return client_initialize_time_events(client);
51debc1e
PF
1369}
1370
4b558378 1371static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) {
4afd3348 1372 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
5ee482df 1373 int r;
3e3d8f78 1374
a6cc569e
TG
1375 r = dhcp_lease_new(&lease);
1376 if (r < 0)
1377 return r;
8c00042c 1378
e37f74a6
DW
1379 if (client->client_id_len) {
1380 r = dhcp_lease_set_client_id(lease,
5bac5235 1381 (uint8_t *) &client->client_id,
e37f74a6
DW
1382 client->client_id_len);
1383 if (r < 0)
1384 return r;
1385 }
1386
f693e9b3 1387 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
9e64dd72 1388 if (r != DHCP_OFFER) {
6ff8806e 1389 log_dhcp_client(client, "received message was not an OFFER, ignoring");
5ee482df 1390 return -ENOMSG;
9e64dd72 1391 }
8c00042c 1392
8e34a618 1393 lease->next_server = offer->siaddr;
e5002702 1394 lease->address = offer->yiaddr;
8c00042c 1395
0339cd77
LP
1396 if (lease->address == 0 ||
1397 lease->server_address == 0 ||
9e64dd72 1398 lease->lifetime == 0) {
0339cd77 1399 log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring");
5ee482df 1400 return -ENOMSG;
9e64dd72
TG
1401 }
1402
0339cd77 1403 if (!lease->have_subnet_mask) {
9e64dd72
TG
1404 r = dhcp_lease_set_default_subnet_mask(lease);
1405 if (r < 0) {
87ac8d99
ZJS
1406 log_dhcp_client(client,
1407 "received lease lacks subnet mask, "
1408 "and a fallback one cannot be generated, ignoring");
9e64dd72
TG
1409 return -ENOMSG;
1410 }
1411 }
8c00042c 1412
6e00a806 1413 sd_dhcp_lease_unref(client->lease);
1cc6c93a 1414 client->lease = TAKE_PTR(lease);
8c00042c 1415
727b5734
SS
1416 if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
1417 return -ENOMSG;
1418
ee57a737
TG
1419 log_dhcp_client(client, "OFFER");
1420
8c00042c 1421 return 0;
8c00042c
PF
1422}
1423
4b558378 1424static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) {
615c1467
TG
1425 int r;
1426
f693e9b3 1427 r = dhcp_option_parse(force, len, NULL, NULL, NULL);
615c1467
TG
1428 if (r != DHCP_FORCERENEW)
1429 return -ENOMSG;
1430
1431 log_dhcp_client(client, "FORCERENEW");
1432
1433 return 0;
1434}
1435
3d9f6707
YW
1436static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) {
1437 if (a->address != b->address)
1438 return false;
1439
1440 if (a->subnet_mask != b->subnet_mask)
1441 return false;
1442
1443 if (a->router_size != b->router_size)
1444 return false;
1445
1446 for (size_t i = 0; i < a->router_size; i++)
1447 if (a->router[i].s_addr != b->router[i].s_addr)
1448 return false;
1449
1450 return true;
1451}
1452
4b558378 1453static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
4afd3348 1454 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
f693e9b3 1455 _cleanup_free_ char *error_message = NULL;
5ee482df 1456 int r;
3e3d8f78 1457
a6cc569e
TG
1458 r = dhcp_lease_new(&lease);
1459 if (r < 0)
1460 return r;
3e3d8f78 1461
e37f74a6
DW
1462 if (client->client_id_len) {
1463 r = dhcp_lease_set_client_id(lease,
5bac5235 1464 (uint8_t *) &client->client_id,
e37f74a6
DW
1465 client->client_id_len);
1466 if (r < 0)
1467 return r;
1468 }
1469
f693e9b3 1470 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
ee57a737 1471 if (r == DHCP_NAK) {
f693e9b3 1472 log_dhcp_client(client, "NAK: %s", strna(error_message));
2d2349cc 1473 return -EADDRNOTAVAIL;
ee57a737 1474 }
3e3d8f78 1475
9e64dd72 1476 if (r != DHCP_ACK) {
6ff8806e 1477 log_dhcp_client(client, "received message was not an ACK, ignoring");
5ee482df 1478 return -ENOMSG;
9e64dd72 1479 }
3e3d8f78 1480
8e34a618
TG
1481 lease->next_server = ack->siaddr;
1482
e5002702 1483 lease->address = ack->yiaddr;
3e3d8f78
PF
1484
1485 if (lease->address == INADDR_ANY ||
1486 lease->server_address == INADDR_ANY ||
9e64dd72 1487 lease->lifetime == 0) {
6ff8806e 1488 log_dhcp_client(client, "received lease lacks address, server "
9e64dd72 1489 "address or lease lifetime, ignoring");
5ee482df 1490 return -ENOMSG;
9e64dd72
TG
1491 }
1492
1493 if (lease->subnet_mask == INADDR_ANY) {
1494 r = dhcp_lease_set_default_subnet_mask(lease);
1495 if (r < 0) {
87ac8d99
ZJS
1496 log_dhcp_client(client,
1497 "received lease lacks subnet mask, "
1498 "and a fallback one cannot be generated, ignoring");
9e64dd72
TG
1499 return -ENOMSG;
1500 }
1501 }
3e3d8f78 1502
03748142 1503 r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
3e3d8f78 1504 if (client->lease) {
3d9f6707 1505 if (lease_equal(client->lease, lease))
03748142 1506 r = SD_DHCP_CLIENT_EVENT_RENEW;
3d9f6707
YW
1507 else
1508 r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
3e3d8f78 1509
a6cc569e 1510 client->lease = sd_dhcp_lease_unref(client->lease);
3e3d8f78
PF
1511 }
1512
1cc6c93a 1513 client->lease = TAKE_PTR(lease);
3e3d8f78 1514
ee57a737
TG
1515 log_dhcp_client(client, "ACK");
1516
3e3d8f78
PF
1517 return r;
1518}
1519
fbcd420a 1520static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) {
022446ad
TG
1521 assert(client);
1522 assert(client->request_sent);
fbcd420a 1523 assert(lifetime > 0);
022446ad 1524
fbcd420a
LP
1525 if (lifetime > 3)
1526 lifetime -= 3;
1527 else
1528 lifetime = 0;
1529
1530 return client->request_sent + (lifetime * USEC_PER_SEC * factor) +
9bf3b535 1531 + (random_u32() & 0x1fffff);
51debc1e
PF
1532}
1533
022446ad
TG
1534static int client_set_lease_timeouts(sd_dhcp_client *client) {
1535 usec_t time_now;
1536 uint64_t lifetime_timeout;
1537 uint64_t t2_timeout;
1538 uint64_t t1_timeout;
1539 char time_string[FORMAT_TIMESPAN_MAX];
5ee482df 1540 int r;
51debc1e 1541
b25ef18b
TG
1542 assert(client);
1543 assert(client->event);
022446ad
TG
1544 assert(client->lease);
1545 assert(client->lease->lifetime);
51debc1e 1546
022446ad 1547 /* don't set timers for infinite leases */
a3fa4287
YW
1548 if (client->lease->lifetime == 0xffffffff) {
1549 (void) event_source_disable(client->timeout_t1);
1550 (void) event_source_disable(client->timeout_t2);
1551 (void) event_source_disable(client->timeout_expire);
1552
022446ad 1553 return 0;
a3fa4287 1554 }
51debc1e 1555
fa94c34b 1556 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
022446ad
TG
1557 if (r < 0)
1558 return r;
1559 assert(client->request_sent <= time_now);
1560
1561 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1562 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
fbcd420a 1563 if (client->lease->t1 > 0 && client->lease->t2 > 0) {
022446ad
TG
1564 /* both T1 and T2 are given */
1565 if (client->lease->t1 < client->lease->t2 &&
1566 client->lease->t2 < client->lease->lifetime) {
1567 /* they are both valid */
1568 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1569 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1570 } else {
1571 /* discard both */
1572 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1573 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1574 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1575 client->lease->t1 = client->lease->lifetime / 2;
1576 }
fbcd420a 1577 } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) {
022446ad
TG
1578 /* only T2 is given, and it is valid */
1579 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1580 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1581 client->lease->t1 = client->lease->lifetime / 2;
1582 if (t2_timeout <= t1_timeout) {
1583 /* the computed T1 would be invalid, so discard T2 */
1584 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1585 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1586 }
fbcd420a 1587 } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) {
022446ad
TG
1588 /* only T1 is given, and it is valid */
1589 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1590 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1591 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1592 if (t2_timeout <= t1_timeout) {
1593 /* the computed T2 would be invalid, so discard T1 */
1594 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1595 client->lease->t2 = client->lease->lifetime / 2;
1596 }
1597 } else {
1598 /* fall back to the default timeouts */
1599 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1600 client->lease->t1 = client->lease->lifetime / 2;
1601 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1602 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1603 }
51debc1e 1604
022446ad 1605 /* arm lifetime timeout */
a3fa4287
YW
1606 r = event_reset_time(client->event, &client->timeout_expire,
1607 clock_boottime_or_monotonic(),
1608 lifetime_timeout, 10 * USEC_PER_MSEC,
1609 client_timeout_expire, client,
1610 client->event_priority, "dhcp4-lifetime", true);
9021bb9f
TG
1611 if (r < 0)
1612 return r;
1613
022446ad 1614 log_dhcp_client(client, "lease expires in %s",
ed19c567 1615 format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
51debc1e 1616
022446ad
TG
1617 /* don't arm earlier timeouts if this has already expired */
1618 if (lifetime_timeout <= time_now)
1619 return 0;
51debc1e 1620
022446ad 1621 /* arm T2 timeout */
a3fa4287
YW
1622 r = event_reset_time(client->event, &client->timeout_t2,
1623 clock_boottime_or_monotonic(),
1624 t2_timeout, 10 * USEC_PER_MSEC,
1625 client_timeout_t2, client,
1626 client->event_priority, "dhcp4-t2-timeout", true);
9021bb9f
TG
1627 if (r < 0)
1628 return r;
1629
022446ad 1630 log_dhcp_client(client, "T2 expires in %s",
ed19c567 1631 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
022446ad
TG
1632
1633 /* don't arm earlier timeout if this has already expired */
1634 if (t2_timeout <= time_now)
1635 return 0;
51debc1e 1636
022446ad 1637 /* arm T1 timeout */
a3fa4287
YW
1638 r = event_reset_time(client->event, &client->timeout_t1,
1639 clock_boottime_or_monotonic(),
1640 t1_timeout, 10 * USEC_PER_MSEC,
1641 client_timeout_t1, client,
1642 client->event_priority, "dhcp4-t1-timer", true);
9021bb9f
TG
1643 if (r < 0)
1644 return r;
1645
022446ad 1646 log_dhcp_client(client, "T1 expires in %s",
ed19c567 1647 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
022446ad 1648
51debc1e
PF
1649 return 0;
1650}
1651
4b558378 1652static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
574cc928 1653 DHCP_CLIENT_DONT_DESTROY(client);
1d1a3e0a 1654 char time_string[FORMAT_TIMESPAN_MAX];
e5002702 1655 int r = 0, notify_event = 0;
8c00042c 1656
b25ef18b
TG
1657 assert(client);
1658 assert(client->event);
e5002702 1659 assert(message);
b25ef18b 1660
8c00042c
PF
1661 switch (client->state) {
1662 case DHCP_STATE_SELECTING:
1663
e5002702
TG
1664 r = client_handle_offer(client, message, len);
1665 if (r >= 0) {
8c00042c 1666
8c00042c 1667 client->state = DHCP_STATE_REQUESTING;
11793fcd 1668 client->attempt = 0;
e2dfc79f 1669
a3fa4287
YW
1670 r = event_reset_time(client->event, &client->timeout_resend,
1671 clock_boottime_or_monotonic(),
1672 0, 0,
1673 client_timeout_resend, client,
1674 client->event_priority, "dhcp4-resend-timer", true);
9021bb9f
TG
1675 if (r < 0)
1676 goto error;
9e64dd72
TG
1677 } else if (r == -ENOMSG)
1678 /* invalid message, let's ignore it */
1679 return 0;
8c00042c
PF
1680
1681 break;
1682
8b1243f7 1683 case DHCP_STATE_REBOOTING:
3e3d8f78 1684 case DHCP_STATE_REQUESTING:
aba26854 1685 case DHCP_STATE_RENEWING:
3dd71400 1686 case DHCP_STATE_REBINDING:
aba26854 1687
e5002702 1688 r = client_handle_ack(client, message, len);
2d2349cc 1689 if (r >= 0) {
1d1a3e0a 1690 client->start_delay = 0;
a3fa4287 1691 (void) event_source_disable(client->timeout_resend);
affaa94f
DW
1692 client->receive_message =
1693 sd_event_source_unref(client->receive_message);
1694 client->fd = asynchronous_close(client->fd);
3e3d8f78 1695
8b1243f7
PF
1696 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1697 DHCP_STATE_REBOOTING))
03748142
DH
1698 notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1699 else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
aba26854
PF
1700 notify_event = r;
1701
3e3d8f78 1702 client->state = DHCP_STATE_BOUND;
11793fcd 1703 client->attempt = 0;
3e3d8f78
PF
1704
1705 client->last_addr = client->lease->address;
1706
022446ad 1707 r = client_set_lease_timeouts(client);
0411760a
TG
1708 if (r < 0) {
1709 log_dhcp_client(client, "could not set lease timeouts");
51debc1e 1710 goto error;
0411760a 1711 }
51debc1e 1712
afe42aef 1713 r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port, client->ip_service_type);
0af03ba5
TG
1714 if (r < 0) {
1715 log_dhcp_client(client, "could not bind UDP socket");
1716 goto error;
1717 }
1718
1719 client->fd = r;
1720
1721 client_initialize_io_events(client, client_receive_message_udp);
1722
e5b04c8d 1723 if (notify_event) {
574cc928
TG
1724 client_notify(client, notify_event);
1725 if (client->state == DHCP_STATE_STOPPED)
e5b04c8d
PF
1726 return 0;
1727 }
3e3d8f78 1728
2d2349cc
TG
1729 } else if (r == -EADDRNOTAVAIL) {
1730 /* got a NAK, let's restart the client */
cc3981b1
LS
1731 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
1732
2d2349cc
TG
1733 r = client_initialize(client);
1734 if (r < 0)
1735 goto error;
1736
1d1a3e0a 1737 r = client_start_delayed(client);
2d2349cc
TG
1738 if (r < 0)
1739 goto error;
1740
1d1a3e0a
BG
1741 log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1742 client->start_delay, USEC_PER_SEC));
1743
1744 client->start_delay = CLAMP(client->start_delay * 2,
1745 RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
2d2349cc
TG
1746
1747 return 0;
9e64dd72
TG
1748 } else if (r == -ENOMSG)
1749 /* invalid message, let's ignore it */
1750 return 0;
97b9372d 1751
3e3d8f78
PF
1752 break;
1753
615c1467
TG
1754 case DHCP_STATE_BOUND:
1755 r = client_handle_forcerenew(client, message, len);
1756 if (r >= 0) {
1757 r = client_timeout_t1(NULL, 0, client);
1758 if (r < 0)
1759 goto error;
1760 } else if (r == -ENOMSG)
1761 /* invalid message, let's ignore it */
1762 return 0;
1763
1764 break;
1765
8c00042c
PF
1766 case DHCP_STATE_INIT:
1767 case DHCP_STATE_INIT_REBOOT:
8c00042c
PF
1768
1769 break;
781ca7a1
PF
1770
1771 case DHCP_STATE_STOPPED:
1772 r = -EINVAL;
1773 goto error;
8c00042c
PF
1774 }
1775
1776error:
2d2349cc 1777 if (r < 0)
e5b04c8d 1778 client_stop(client, r);
e2dfc79f 1779
e5b04c8d 1780 return r;
8c00042c
PF
1781}
1782
4b558378
ZJS
1783static int client_receive_message_udp(
1784 sd_event_source *s,
1785 int fd,
1786 uint32_t revents,
1787 void *userdata) {
1788
e5002702 1789 sd_dhcp_client *client = userdata;
5266a81e 1790 _cleanup_free_ DHCPMessage *message = NULL;
13f1fd03 1791 const uint8_t *expected_chaddr = NULL;
76253e73 1792 uint8_t expected_hlen = 0;
4edc2c9b 1793 ssize_t len, buflen;
e5002702
TG
1794
1795 assert(s);
1796 assert(client);
e5002702 1797
4edc2c9b 1798 buflen = next_datagram_size_fd(fd);
22a3fd2d
BG
1799 if (buflen == -ENETDOWN) {
1800 /* the link is down. Don't return an error or the I/O event
1801 source will be disconnected and we won't be able to receive
1802 packets again when the link comes back. */
1803 return 0;
1804 }
4edc2c9b
LP
1805 if (buflen < 0)
1806 return buflen;
5266a81e
TG
1807
1808 message = malloc0(buflen);
1809 if (!message)
1810 return -ENOMEM;
1811
cf447cb6 1812 len = recv(fd, message, buflen, 0);
0c79c68d 1813 if (len < 0) {
22a3fd2d
BG
1814 /* see comment above for why we shouldn't error out on ENETDOWN. */
1815 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
0d43d2fc
TG
1816 return 0;
1817
25f027c5
ZJS
1818 return log_dhcp_client_errno(client, errno,
1819 "Could not receive message from UDP socket: %m");
004845d1
LP
1820 }
1821 if ((size_t) len < sizeof(DHCPMessage)) {
0d43d2fc 1822 log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
e5002702 1823 return 0;
9fbc2523
TG
1824 }
1825
1826 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
0d43d2fc 1827 log_dhcp_client(client, "Not a DHCP message: ignoring");
9fbc2523
TG
1828 return 0;
1829 }
1830
1831 if (message->op != BOOTREPLY) {
0d43d2fc 1832 log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
9fbc2523
TG
1833 return 0;
1834 }
1835
76253e73 1836 if (message->htype != client->arp_type) {
0d43d2fc 1837 log_dhcp_client(client, "Packet type does not match client type");
76253e73
DW
1838 return 0;
1839 }
1840
1841 if (client->arp_type == ARPHRD_ETHER) {
1842 expected_hlen = ETH_ALEN;
13f1fd03 1843 expected_chaddr = &client->mac_addr[0];
76253e73
DW
1844 }
1845
1846 if (message->hlen != expected_hlen) {
0d43d2fc 1847 log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
9fbc2523
TG
1848 return 0;
1849 }
1850
13f1fd03 1851 if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) {
0d43d2fc 1852 log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
9fbc2523
TG
1853 return 0;
1854 }
e5002702 1855
615c1467
TG
1856 if (client->state != DHCP_STATE_BOUND &&
1857 be32toh(message->xid) != client->xid) {
1858 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1859 so ignore the xid in this case */
0d43d2fc 1860 log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
615c1467
TG
1861 be32toh(message->xid), client->xid);
1862 return 0;
1863 }
1864
022446ad 1865 return client_handle_message(client, message, len);
e5002702
TG
1866}
1867
4b558378
ZJS
1868static int client_receive_message_raw(
1869 sd_event_source *s,
1870 int fd,
1871 uint32_t revents,
1872 void *userdata) {
1873
e5002702 1874 sd_dhcp_client *client = userdata;
5266a81e 1875 _cleanup_free_ DHCPPacket *packet = NULL;
55dab2ed
TG
1876 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1877 struct iovec iov = {};
1878 struct msghdr msg = {
1879 .msg_iov = &iov,
1880 .msg_iovlen = 1,
1881 .msg_control = cmsgbuf,
1882 .msg_controllen = sizeof(cmsgbuf),
1883 };
1884 struct cmsghdr *cmsg;
1885 bool checksum = true;
4edc2c9b
LP
1886 ssize_t buflen, len;
1887 int r;
e5002702
TG
1888
1889 assert(s);
1890 assert(client);
e5002702 1891
4edc2c9b 1892 buflen = next_datagram_size_fd(fd);
22a3fd2d
BG
1893 if (buflen == -ENETDOWN)
1894 return 0;
4edc2c9b
LP
1895 if (buflen < 0)
1896 return buflen;
5266a81e
TG
1897
1898 packet = malloc0(buflen);
1899 if (!packet)
1900 return -ENOMEM;
1901
cb310866 1902 iov = IOVEC_MAKE(packet, buflen);
55dab2ed 1903
a38d9945 1904 len = recvmsg(fd, &msg, 0);
55dab2ed 1905 if (len < 0) {
22a3fd2d 1906 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
0d43d2fc
TG
1907 return 0;
1908
25f027c5
ZJS
1909 return log_dhcp_client_errno(client, errno,
1910 "Could not receive message from raw socket: %m");
0c79c68d
TG
1911 } else if ((size_t)len < sizeof(DHCPPacket))
1912 return 0;
55dab2ed 1913
e4a0fe63 1914 CMSG_FOREACH(cmsg, &msg)
48a4612e
TG
1915 if (cmsg->cmsg_level == SOL_PACKET &&
1916 cmsg->cmsg_type == PACKET_AUXDATA &&
1917 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1918 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
55dab2ed
TG
1919
1920 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1921 break;
1922 }
e5002702 1923
9faed222 1924 r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
ac4f16ab 1925 if (r < 0)
9fadd4ca 1926 return 0;
e5002702
TG
1927
1928 len -= DHCP_IP_UDP_SIZE;
1929
022446ad 1930 return client_handle_message(client, &packet->dhcp, len);
e5002702
TG
1931}
1932
1c9a2e26
YW
1933int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
1934 assert_return(client, -EINVAL);
1935 assert_return(client->fd >= 0, -EINVAL);
1936
1937 client->start_delay = 0;
1938 client->attempt = 1;
1939 client->state = DHCP_STATE_RENEWING;
1940
1941 return client_initialize_time_events(client);
1942}
1943
5ee482df 1944int sd_dhcp_client_start(sd_dhcp_client *client) {
6a1cd41e 1945 int r;
d3d8ac2f 1946
46a66b79 1947 assert_return(client, -EINVAL);
46a66b79 1948
0f941add
PF
1949 r = client_initialize(client);
1950 if (r < 0)
6a1cd41e 1951 return r;
8c00042c 1952
66173db7 1953 /* RFC7844 section 3.3:
1954 SHOULD perform a complete four-way handshake, starting with a
1955 DHCPDISCOVER, to obtain a new address lease. If the client can
1956 ascertain that this is exactly the same network to which it was
1957 previously connected, and if the link-layer address did not change,
1958 the client MAY issue a DHCPREQUEST to try to reclaim the current
1959 address. */
1960 if (client->last_addr && !client->anonymize)
0f941add 1961 client->state = DHCP_STATE_INIT_REBOOT;
d3d8ac2f 1962
998d8047
TG
1963 r = client_start(client);
1964 if (r >= 0)
2f8e7633 1965 log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex);
998d8047
TG
1966
1967 return r;
46a66b79
PF
1968}
1969
1501b429
SS
1970int sd_dhcp_client_send_release(sd_dhcp_client *client) {
1971 assert_return(client, -EINVAL);
8ff4585f 1972 assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
8bea7e70 1973 assert_return(client->lease, -EUNATCH);
8ff4585f
ZJS
1974
1975 _cleanup_free_ DHCPPacket *release = NULL;
1976 size_t optoffset, optlen;
1977 int r;
1978
1979 r = client_message_init(client, &release, DHCP_RELEASE, &optlen, &optoffset);
1980 if (r < 0)
1981 return r;
1982
1983 /* Fill up release IP and MAC */
1984 release->dhcp.ciaddr = client->lease->address;
1985 memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
1501b429 1986
8ff4585f
ZJS
1987 r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
1988 SD_DHCP_OPTION_END, 0, NULL);
1989 if (r < 0)
1990 return r;
1991
1992 r = dhcp_network_send_udp_socket(client->fd,
1993 client->lease->server_address,
1994 DHCP_PORT_SERVER,
1995 &release->dhcp,
1996 sizeof(DHCPMessage) + optoffset);
1997 if (r < 0)
1998 return r;
1999
2000 log_dhcp_client(client, "RELEASE");
1501b429
SS
2001
2002 return 0;
2003}
2004
5ee482df 2005int sd_dhcp_client_stop(sd_dhcp_client *client) {
574cc928
TG
2006 DHCP_CLIENT_DONT_DESTROY(client);
2007
e5b04c8d
PF
2008 assert_return(client, -EINVAL);
2009
03748142 2010 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
574cc928 2011 client->state = DHCP_STATE_STOPPED;
e5b04c8d
PF
2012
2013 return 0;
bbdf06d9
PF
2014}
2015
32d20645 2016int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
b25ef18b
TG
2017 int r;
2018
2019 assert_return(client, -EINVAL);
2020 assert_return(!client->event, -EBUSY);
2021
2022 if (event)
2023 client->event = sd_event_ref(event);
2024 else {
2025 r = sd_event_default(&client->event);
2026 if (r < 0)
2027 return 0;
2028 }
2029
2030 client->event_priority = priority;
2031
2032 return 0;
2033}
2034
2035int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
2036 assert_return(client, -EINVAL);
2037
2038 client->event = sd_event_unref(client->event);
2039
2040 return 0;
2041}
2042
2043sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
a1140666 2044 assert_return(client, NULL);
b25ef18b
TG
2045
2046 return client->event;
2047}
2048
8301aa0b
YW
2049static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
2050 assert(client);
e5b04c8d 2051
3733eec3 2052 log_dhcp_client(client, "FREE");
6e00a806 2053
a3fa4287
YW
2054 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
2055 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
2056 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
2057 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
3733eec3 2058
a3fa4287 2059 client_initialize(client);
3733eec3
LP
2060
2061 sd_dhcp_client_detach_event(client);
2062
2063 sd_dhcp_lease_unref(client->lease);
2064
2065 free(client->req_opts);
2066 free(client->hostname);
2067 free(client->vendor_class_identifier);
af1c0de0 2068 client->user_class = strv_free(client->user_class);
cb29c156 2069 ordered_hashmap_free(client->options);
6b430fdb 2070 return mfree(client);
d2fe46b5
PF
2071}
2072
8301aa0b
YW
2073DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
2074
db3d2358 2075int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
4afd3348 2076 _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
011feef8 2077
b25ef18b 2078 assert_return(ret, -EINVAL);
d3d8ac2f 2079
be6bf4a7 2080 client = new(sd_dhcp_client, 1);
011feef8 2081 if (!client)
b25ef18b 2082 return -ENOMEM;
011feef8 2083
be6bf4a7
YW
2084 *client = (sd_dhcp_client) {
2085 .n_ref = 1,
2086 .state = DHCP_STATE_INIT,
2087 .ifindex = -1,
2088 .fd = -1,
be6bf4a7
YW
2089 .mtu = DHCP_DEFAULT_MIN_SIZE,
2090 .port = DHCP_PORT_CLIENT,
2091 .anonymize = !!anonymize,
715cedfb 2092 .max_attempts = (uint64_t) -1,
afe42aef 2093 .ip_service_type = -1,
be6bf4a7 2094 };
db3d2358 2095 /* NOTE: this could be moved to a function. */
2096 if (anonymize) {
2097 client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
2098 client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
2099 } else {
2100 client->req_opts_size = ELEMENTSOF(default_req_opts);
2101 client->req_opts = memdup(default_req_opts, client->req_opts_size);
2102 }
b25ef18b
TG
2103 if (!client->req_opts)
2104 return -ENOMEM;
2105
1cc6c93a 2106 *ret = TAKE_PTR(client);
011feef8 2107
b25ef18b 2108 return 0;
011feef8 2109}