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