]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-client.c
Merge pull request #13828 from keszybz/networkctl-print-wlan
[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) {
551 _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *p = NULL;
552 _cleanup_free_ void *q = NULL;
553
554 assert(ret);
555
556 q = memdup(data, length);
557 if (!q)
558 return -ENOMEM;
559
560 p = new(sd_dhcp_option, 1);
561 if (!p)
562 return -ENOMEM;
563
564 *p = (sd_dhcp_option) {
565 .n_ref = 1,
566 .option = option,
567 .length = length,
568 .data = TAKE_PTR(q),
569 };
570
571 *ret = TAKE_PTR(p);
572 return 0;
573}
574
575DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_option, sd_dhcp_option, dhcp_option_free);
576DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
577 dhcp_option_hash_ops,
578 void,
579 trivial_hash_func,
580 trivial_compare_func,
581 sd_dhcp_option,
582 sd_dhcp_option_unref);
583
584int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) {
585 int r;
586
587 assert_return(client, -EINVAL);
588 assert_return(v, -EINVAL);
589
590 r = ordered_hashmap_ensure_allocated(&client->options, &dhcp_option_hash_ops);
591 if (r < 0)
592 return r;
593
594 r = ordered_hashmap_put(client->options, UINT_TO_PTR(v->option), v);
595 if (r < 0)
596 return r;
597
598 sd_dhcp_option_ref(v);
599 return 0;
600}
601
a6cc569e 602int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
751246ee 603 assert_return(client, -EINVAL);
751246ee 604
727b5734 605 if (!IN_SET(client->state, DHCP_STATE_SELECTING, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING))
a6cc569e 606 return -EADDRNOTAVAIL;
751246ee 607
a1140666
LP
608 if (ret)
609 *ret = client->lease;
4f882b2a
TG
610
611 return 0;
612}
613
afe42aef
SC
614int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
615 assert_return(client, -EINVAL);
616
617 client->ip_service_type = type;
618
619 return 0;
620}
621
727b5734 622static int client_notify(sd_dhcp_client *client, int event) {
45aa74c7
LP
623 assert(client);
624
625 if (client->callback)
727b5734
SS
626 return client->callback(client, event, client->userdata);
627
628 return 0;
3e3d8f78
PF
629}
630
0f941add 631static int client_initialize(sd_dhcp_client *client) {
bbdf06d9 632 assert_return(client, -EINVAL);
bbdf06d9 633
a1140666 634 client->receive_message = sd_event_source_unref(client->receive_message);
8c00042c 635
22fc2420 636 client->fd = asynchronous_close(client->fd);
8c00042c 637
a3fa4287
YW
638 (void) event_source_disable(client->timeout_resend);
639 (void) event_source_disable(client->timeout_t1);
640 (void) event_source_disable(client->timeout_t2);
641 (void) event_source_disable(client->timeout_expire);
51debc1e 642
11793fcd 643 client->attempt = 0;
e2dfc79f 644
f8fdefe4 645 client->state = DHCP_STATE_INIT;
0f941add 646 client->xid = 0;
bbdf06d9 647
0339cd77 648 client->lease = sd_dhcp_lease_unref(client->lease);
8c00042c 649
0f941add
PF
650 return 0;
651}
652
574cc928
TG
653static void client_stop(sd_dhcp_client *client, int error) {
654 assert(client);
0f941add 655
ccfdc9a1 656 if (error < 0)
7fa6223f 657 log_dhcp_client_errno(client, error, "STOPPED: %m");
03748142 658 else if (error == SD_DHCP_CLIENT_EVENT_STOP)
2d2349cc
TG
659 log_dhcp_client(client, "STOPPED");
660 else
661 log_dhcp_client(client, "STOPPED: Unknown event");
0f941add 662
574cc928 663 client_notify(client, error);
ee57a737 664
574cc928 665 client_initialize(client);
bbdf06d9
PF
666}
667
4b558378
ZJS
668static int client_message_init(
669 sd_dhcp_client *client,
670 DHCPPacket **ret,
671 uint8_t type,
672 size_t *_optlen,
673 size_t *_optoffset) {
674
3587161a 675 _cleanup_free_ DHCPPacket *packet = NULL;
424a8732 676 size_t optlen, optoffset, size;
8a9e7616 677 be16_t max_size;
d8d74ef0
DW
678 usec_t time_now;
679 uint16_t secs;
cf597f65 680 int r;
46a66b79 681
6236f49b 682 assert(client);
d8d74ef0 683 assert(client->start_time);
424a8732
TG
684 assert(ret);
685 assert(_optlen);
686 assert(_optoffset);
1501b429 687 assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE));
0a1b6da8 688
424a8732
TG
689 optlen = DHCP_MIN_OPTIONS_SIZE;
690 size = sizeof(DHCPPacket) + optlen;
691
692 packet = malloc0(size);
693 if (!packet)
694 return -ENOMEM;
695
696 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
76253e73 697 client->arp_type, optlen, &optoffset);
cf597f65
TG
698 if (r < 0)
699 return r;
46a66b79 700
0a1b6da8
TG
701 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
702 refuse to issue an DHCP lease if 'secs' is set to zero */
d8d74ef0
DW
703 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
704 if (r < 0)
705 return r;
706 assert(time_now >= client->start_time);
707
708 /* seconds between sending first and last DISCOVER
709 * must always be strictly positive to deal with broken servers */
710 secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
711 packet->dhcp.secs = htobe16(secs);
0a1b6da8 712
63a07041
CA
713 /* RFC2132 section 4.1
714 A client that cannot receive unicast IP datagrams until its protocol
715 software has been configured with an IP address SHOULD set the
716 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
717 DHCPREQUEST messages that client sends. The BROADCAST bit will
718 provide a hint to the DHCP server and BOOTP relay agent to broadcast
f5de5b00
TG
719 any messages to the client on the client's subnet.
720
721 Note: some interfaces needs this to be enabled, but some networks
722 needs this to be disabled as broadcasts are filteretd, so this
723 needs to be configurable */
76253e73 724 if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
f5de5b00 725 packet->dhcp.flags = htobe16(0x8000);
63a07041 726
50d6810e
TG
727 /* RFC2132 section 4.1.1:
728 The client MUST include its hardware address in the ’chaddr’ field, if
76253e73
DW
729 necessary for delivery of DHCP reply messages. Non-Ethernet
730 interfaces will leave 'chaddr' empty and use the client identifier
731 instead (eg, RFC 4390 section 2.1).
50d6810e 732 */
76253e73
DW
733 if (client->arp_type == ARPHRD_ETHER)
734 memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
f5a70de7 735
afec4539 736 /* If no client identifier exists, construct an RFC 4361-compliant one */
5bac5235
TG
737 if (client->client_id_len == 0) {
738 size_t duid_len;
739
740 client->client_id.type = 255;
741
6d13616b
TH
742 r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
743 true, &client->client_id.ns.iaid);
5bac5235
TG
744 if (r < 0)
745 return r;
746
747 r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len);
748 if (r < 0)
749 return r;
750
751 client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
ba6c0fd6
DW
752 }
753
ee57a737 754 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
46a66b79 755 Identifier option is not set */
ba6c0fd6
DW
756 if (client->client_id_len) {
757 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
22805d92 758 SD_DHCP_OPTION_CLIENT_IDENTIFIER,
ba6c0fd6 759 client->client_id_len,
5bac5235 760 &client->client_id);
ba6c0fd6
DW
761 if (r < 0)
762 return r;
763 }
50d6810e
TG
764
765 /* RFC2131 section 3.5:
766 in its initial DHCPDISCOVER or DHCPREQUEST message, a
767 client may provide the server with a list of specific
768 parameters the client is interested in. If the client
769 includes a list of parameters in a DHCPDISCOVER message,
770 it MUST include that list in any subsequent DHCPREQUEST
771 messages.
772 */
5e77a146 773
774 /* RFC7844 section 3:
775 MAY contain the Parameter Request List option. */
776 /* NOTE: in case that there would be an option to do not send
777 * any PRL at all, the size should be checked before sending */
1501b429 778 if (client->req_opts_size > 0 && type != DHCP_RELEASE) {
5e77a146 779 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
780 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
781 client->req_opts_size, client->req_opts);
782 if (r < 0)
783 return r;
784 }
8a9e7616 785
50d6810e
TG
786 /* RFC2131 section 3.5:
787 The client SHOULD include the ’maximum DHCP message size’ option to
788 let the server know how large the server may make its DHCP messages.
789
790 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
f21f31b2 791 than the defined default size unless the Maximum Message Size option
f131770b 792 is explicitly set
324f8187
TG
793
794 RFC3442 "Requirements to Avoid Sizing Constraints":
795 Because a full routing table can be quite large, the standard 576
796 octet maximum size for a DHCP message may be too short to contain
797 some legitimate Classless Static Route options. Because of this,
798 clients implementing the Classless Static Route option SHOULD send a
799 Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
800 stack is capable of receiving larger IP datagrams. In this case, the
801 client SHOULD set the value of this option to at least the MTU of the
802 interface that the client is configuring. The client MAY set the
803 value of this option higher, up to the size of the largest UDP packet
804 it is prepared to accept. (Note that the value specified in the
805 Maximum DHCP Message Size option is the total maximum packet size,
806 including IP and UDP headers.)
50d6810e 807 */
1b41b815 808 /* RFC7844 section 3:
809 SHOULD NOT contain any other option. */
1501b429 810 if (!client->anonymize && type != DHCP_RELEASE) {
1b41b815 811 max_size = htobe16(size);
812 r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
813 SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
814 2, &max_size);
815 if (r < 0)
816 return r;
817 }
46a66b79 818
424a8732
TG
819 *_optlen = optlen;
820 *_optoffset = optoffset;
1cc6c93a 821 *ret = TAKE_PTR(packet);
424a8732 822
46a66b79
PF
823 return 0;
824}
825
4b558378
ZJS
826static int client_append_fqdn_option(
827 DHCPMessage *message,
828 size_t optlen,
829 size_t *optoffset,
830 const char *fqdn) {
831
23873e25
BG
832 uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
833 int r;
834
835 buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
836 DHCP_FQDN_FLAG_E; /* Canonical wire format */
837 buffer[1] = 0; /* RCODE1 (deprecated) */
838 buffer[2] = 0; /* RCODE2 (deprecated) */
839
3cd03457 840 r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false);
23873e25
BG
841 if (r > 0)
842 r = dhcp_option_append(message, optlen, optoffset, 0,
22805d92 843 SD_DHCP_OPTION_FQDN, 3 + r, buffer);
23873e25
BG
844
845 return r;
846}
847
4b558378
ZJS
848static int dhcp_client_send_raw(
849 sd_dhcp_client *client,
850 DHCPPacket *packet,
851 size_t len) {
852
9faed222 853 dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
afe42aef 854 INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type);
63edaa62
TG
855
856 return dhcp_network_send_raw_socket(client->fd, &client->link,
857 packet, len);
858}
859
6236f49b 860static int client_send_discover(sd_dhcp_client *client) {
9f2a50a3 861 _cleanup_free_ DHCPPacket *discover = NULL;
424a8732 862 size_t optoffset, optlen;
cb29c156
SS
863 sd_dhcp_option *j;
864 Iterator i;
6236f49b
TG
865 int r;
866
867 assert(client);
4c701096 868 assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
50d6810e 869
424a8732
TG
870 r = client_message_init(client, &discover, DHCP_DISCOVER,
871 &optlen, &optoffset);
6236f49b
TG
872 if (r < 0)
873 return r;
46a66b79 874
50d6810e
TG
875 /* the client may suggest values for the network address
876 and lease time in the DHCPDISCOVER message. The client may include
877 the ’requested IP address’ option to suggest that a particular IP
878 address be assigned, and may include the ’IP address lease time’
879 option to suggest the lease time it would like.
880 */
46a66b79 881 if (client->last_addr != INADDR_ANY) {
04b28be1 882 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 883 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
20b958bf 884 4, &client->last_addr);
6236f49b
TG
885 if (r < 0)
886 return r;
46a66b79
PF
887 }
888
4cc7a82c 889 if (client->hostname) {
23873e25
BG
890 /* According to RFC 4702 "clients that send the Client FQDN option in
891 their messages MUST NOT also send the Host Name option". Just send
892 one of the two depending on the hostname type.
893 */
dc477e73 894 if (dns_name_is_single_label(client->hostname)) {
23873e25
BG
895 /* it is unclear from RFC 2131 if client should send hostname in
896 DHCPDISCOVER but dhclient does and so we do as well
897 */
898 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 899 SD_DHCP_OPTION_HOST_NAME,
23873e25
BG
900 strlen(client->hostname), client->hostname);
901 } else
902 r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
903 client->hostname);
4cc7a82c
EY
904 if (r < 0)
905 return r;
906 }
907
edb85f0d
SS
908 if (client->vendor_class_identifier) {
909 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 910 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
edb85f0d
SS
911 strlen(client->vendor_class_identifier),
912 client->vendor_class_identifier);
913 if (r < 0)
914 return r;
915 }
916
af1c0de0
SS
917 if (client->user_class) {
918 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
919 SD_DHCP_OPTION_USER_CLASS,
920 strv_length(client->user_class),
921 client->user_class);
922 if (r < 0)
923 return r;
924 }
925
cb29c156
SS
926 ORDERED_HASHMAP_FOREACH(j, client->options, i) {
927 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
928 j->option, j->length, j->data);
929 if (r < 0)
930 return r;
931 }
932
04b28be1 933 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 934 SD_DHCP_OPTION_END, 0, NULL);
f7926298
TA
935 if (r < 0)
936 return r;
46a66b79 937
50d6810e
TG
938 /* We currently ignore:
939 The client SHOULD wait a random time between one and ten seconds to
940 desynchronize the use of DHCP at startup.
941 */
20b958bf 942 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
6236f49b
TG
943 if (r < 0)
944 return r;
e2dfc79f 945
ee57a737
TG
946 log_dhcp_client(client, "DISCOVER");
947
63edaa62 948 return 0;
e2dfc79f
PF
949}
950
6236f49b 951static int client_send_request(sd_dhcp_client *client) {
8186d9dd 952 _cleanup_free_ DHCPPacket *request = NULL;
424a8732 953 size_t optoffset, optlen;
6236f49b 954 int r;
e2dfc79f 955
a1140666
LP
956 assert(client);
957
958 r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset);
6236f49b
TG
959 if (r < 0)
960 return r;
46a66b79 961
8b1243f7 962 switch (client->state) {
50d6810e
TG
963 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
964 SELECTING should be REQUESTING)
965 */
966
967 case DHCP_STATE_REQUESTING:
968 /* Client inserts the address of the selected server in ’server
969 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
970 filled in with the yiaddr value from the chosen DHCPOFFER.
971 */
8b1243f7 972
04b28be1 973 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 974 SD_DHCP_OPTION_SERVER_IDENTIFIER,
50d6810e 975 4, &client->lease->server_address);
6236f49b
TG
976 if (r < 0)
977 return r;
8b1243f7 978
04b28be1 979 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 980 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
6236f49b
TG
981 4, &client->lease->address);
982 if (r < 0)
983 return r;
984
50d6810e
TG
985 break;
986
987 case DHCP_STATE_INIT_REBOOT:
988 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
989 option MUST be filled in with client’s notion of its previously
990 assigned address. ’ciaddr’ MUST be zero.
991 */
04b28be1 992 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 993 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
50d6810e 994 4, &client->last_addr);
6236f49b
TG
995 if (r < 0)
996 return r;
8b1243f7
PF
997 break;
998
8b1243f7 999 case DHCP_STATE_RENEWING:
50d6810e
TG
1000 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1001 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
1002 client’s IP address.
1003 */
1004
8b1243f7 1005 case DHCP_STATE_REBINDING:
50d6810e
TG
1006 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1007 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
1008 client’s IP address.
1009
1010 This message MUST be broadcast to the 0xffffffff IP broadcast address.
1011 */
1012 request->dhcp.ciaddr = client->lease->address;
8b1243f7
PF
1013
1014 break;
781ca7a1 1015
50d6810e
TG
1016 case DHCP_STATE_INIT:
1017 case DHCP_STATE_SELECTING:
1018 case DHCP_STATE_REBOOTING:
1019 case DHCP_STATE_BOUND:
781ca7a1
PF
1020 case DHCP_STATE_STOPPED:
1021 return -EINVAL;
e2dfc79f 1022 }
46a66b79 1023
4cc7a82c 1024 if (client->hostname) {
dc477e73 1025 if (dns_name_is_single_label(client->hostname))
23873e25 1026 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 1027 SD_DHCP_OPTION_HOST_NAME,
23873e25
BG
1028 strlen(client->hostname), client->hostname);
1029 else
1030 r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
1031 client->hostname);
4cc7a82c
EY
1032 if (r < 0)
1033 return r;
1034 }
1035
5153494f
AG
1036 if (client->vendor_class_identifier) {
1037 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
1038 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
1039 strlen(client->vendor_class_identifier),
1040 client->vendor_class_identifier);
1041 if (r < 0)
1042 return r;
1043 }
1044
04b28be1 1045 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 1046 SD_DHCP_OPTION_END, 0, NULL);
6236f49b
TG
1047 if (r < 0)
1048 return r;
46a66b79 1049
bdbb98d9 1050 if (client->state == DHCP_STATE_RENEWING)
6236f49b
TG
1051 r = dhcp_network_send_udp_socket(client->fd,
1052 client->lease->server_address,
1053 DHCP_PORT_SERVER,
1054 &request->dhcp,
20b958bf 1055 sizeof(DHCPMessage) + optoffset);
bdbb98d9 1056 else
20b958bf 1057 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
6236f49b
TG
1058 if (r < 0)
1059 return r;
46a66b79 1060
998d8047 1061 switch (client->state) {
a1140666 1062
998d8047
TG
1063 case DHCP_STATE_REQUESTING:
1064 log_dhcp_client(client, "REQUEST (requesting)");
1065 break;
a1140666 1066
998d8047
TG
1067 case DHCP_STATE_INIT_REBOOT:
1068 log_dhcp_client(client, "REQUEST (init-reboot)");
1069 break;
a1140666 1070
998d8047
TG
1071 case DHCP_STATE_RENEWING:
1072 log_dhcp_client(client, "REQUEST (renewing)");
1073 break;
a1140666 1074
998d8047
TG
1075 case DHCP_STATE_REBINDING:
1076 log_dhcp_client(client, "REQUEST (rebinding)");
1077 break;
a1140666 1078
998d8047
TG
1079 default:
1080 log_dhcp_client(client, "REQUEST (invalid)");
1081 break;
1082 }
ee57a737 1083
63edaa62 1084 return 0;
46a66b79
PF
1085}
1086
7739a40b
TG
1087static int client_start(sd_dhcp_client *client);
1088
4b558378
ZJS
1089static int client_timeout_resend(
1090 sd_event_source *s,
1091 uint64_t usec,
1092 void *userdata) {
1093
d3d8ac2f 1094 sd_dhcp_client *client = userdata;
574cc928 1095 DHCP_CLIENT_DONT_DESTROY(client);
aba26854 1096 usec_t next_timeout = 0;
d23c45bf 1097 uint64_t time_now;
aba26854 1098 uint32_t time_left;
d23c45bf 1099 int r;
b25ef18b
TG
1100
1101 assert(s);
1102 assert(client);
1103 assert(client->event);
d3d8ac2f 1104
fa94c34b 1105 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
d23c45bf
TG
1106 if (r < 0)
1107 goto error;
1108
aba26854 1109 switch (client->state) {
a1140666 1110
aba26854
PF
1111 case DHCP_STATE_RENEWING:
1112
e5002702 1113 time_left = (client->lease->t2 - client->lease->t1) / 2;
aba26854
PF
1114 if (time_left < 60)
1115 time_left = 60;
d3d8ac2f 1116
d23c45bf 1117 next_timeout = time_now + time_left * USEC_PER_SEC;
d3d8ac2f 1118
aba26854
PF
1119 break;
1120
3dd71400
PF
1121 case DHCP_STATE_REBINDING:
1122
e5002702 1123 time_left = (client->lease->lifetime - client->lease->t2) / 2;
3dd71400
PF
1124 if (time_left < 60)
1125 time_left = 60;
1126
d23c45bf 1127 next_timeout = time_now + time_left * USEC_PER_SEC;
3dd71400
PF
1128 break;
1129
8b1243f7
PF
1130 case DHCP_STATE_REBOOTING:
1131 /* start over as we did not receive a timely ack or nak */
7739a40b 1132 r = client_initialize(client);
eb105b96
TG
1133 if (r < 0)
1134 goto error;
8b1243f7 1135
998d8047
TG
1136 r = client_start(client);
1137 if (r < 0)
1138 goto error;
1139 else {
1140 log_dhcp_client(client, "REBOOTED");
1141 return 0;
1142 }
7739a40b 1143
aba26854
PF
1144 case DHCP_STATE_INIT:
1145 case DHCP_STATE_INIT_REBOOT:
aba26854
PF
1146 case DHCP_STATE_SELECTING:
1147 case DHCP_STATE_REQUESTING:
1148 case DHCP_STATE_BOUND:
aba26854 1149
715cedfb 1150 if (client->attempt < client->max_attempts)
11793fcd 1151 client->attempt++;
8bc17bb3
SS
1152 else
1153 goto error;
aba26854 1154
715cedfb 1155 next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
aba26854
PF
1156
1157 break;
781ca7a1
PF
1158
1159 case DHCP_STATE_STOPPED:
1160 r = -EINVAL;
1161 goto error;
aba26854
PF
1162 }
1163
9bf3b535 1164 next_timeout += (random_u32() & 0x1fffff);
d3d8ac2f 1165
a3fa4287
YW
1166 r = event_reset_time(client->event, &client->timeout_resend,
1167 clock_boottime_or_monotonic(),
1168 next_timeout, 10 * USEC_PER_MSEC,
1169 client_timeout_resend, client,
1170 client->event_priority, "dhcp4-resend-timer", true);
9021bb9f
TG
1171 if (r < 0)
1172 goto error;
1173
e2dfc79f
PF
1174 switch (client->state) {
1175 case DHCP_STATE_INIT:
6236f49b 1176 r = client_send_discover(client);
b25ef18b 1177 if (r >= 0) {
e2dfc79f 1178 client->state = DHCP_STATE_SELECTING;
11793fcd 1179 client->attempt = 0;
715cedfb
SS
1180 } else if (client->attempt >= client->max_attempts)
1181 goto error;
e2dfc79f
PF
1182
1183 break;
1184
1185 case DHCP_STATE_SELECTING:
6236f49b 1186 r = client_send_discover(client);
715cedfb 1187 if (r < 0 && client->attempt >= client->max_attempts)
d3d8ac2f
PF
1188 goto error;
1189
e2dfc79f
PF
1190 break;
1191
8b1243f7 1192 case DHCP_STATE_INIT_REBOOT:
e2dfc79f 1193 case DHCP_STATE_REQUESTING:
aba26854 1194 case DHCP_STATE_RENEWING:
3dd71400 1195 case DHCP_STATE_REBINDING:
6236f49b 1196 r = client_send_request(client);
715cedfb 1197 if (r < 0 && client->attempt >= client->max_attempts)
e2dfc79f 1198 goto error;
d3d8ac2f 1199
8b1243f7
PF
1200 if (client->state == DHCP_STATE_INIT_REBOOT)
1201 client->state = DHCP_STATE_REBOOTING;
1202
d23c45bf 1203 client->request_sent = time_now;
51debc1e 1204
d3d8ac2f
PF
1205 break;
1206
d3d8ac2f 1207 case DHCP_STATE_REBOOTING:
d3d8ac2f 1208 case DHCP_STATE_BOUND:
d3d8ac2f
PF
1209
1210 break;
781ca7a1
PF
1211
1212 case DHCP_STATE_STOPPED:
1213 r = -EINVAL;
1214 goto error;
d3d8ac2f
PF
1215 }
1216
1217 return 0;
1218
1219error:
b25ef18b 1220 client_stop(client, r);
d3d8ac2f
PF
1221
1222 /* Errors were dealt with when stopping the client, don't spill
1223 errors into the event loop handler */
1224 return 0;
1225}
1226
4b558378
ZJS
1227static int client_initialize_io_events(
1228 sd_dhcp_client *client,
1229 sd_event_io_handler_t io_callback) {
1230
6a1cd41e
PF
1231 int r;
1232
b25ef18b
TG
1233 assert(client);
1234 assert(client->event);
1235
151b9b96
LP
1236 r = sd_event_add_io(client->event, &client->receive_message,
1237 client->fd, EPOLLIN, io_callback,
1238 client);
6a1cd41e
PF
1239 if (r < 0)
1240 goto error;
1241
e5002702
TG
1242 r = sd_event_source_set_priority(client->receive_message,
1243 client->event_priority);
b25ef18b
TG
1244 if (r < 0)
1245 goto error;
1246
356779df 1247 r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
9021bb9f
TG
1248 if (r < 0)
1249 goto error;
1250
0af03ba5
TG
1251error:
1252 if (r < 0)
1253 client_stop(client, r);
1254
1255 return 0;
1256}
1257
1258static int client_initialize_time_events(sd_dhcp_client *client) {
1d1a3e0a 1259 uint64_t usec = 0;
0af03ba5
TG
1260 int r;
1261
1262 assert(client);
1263 assert(client->event);
1264
bdbb98d9 1265 if (client->start_delay > 0) {
8ecdcb55 1266 assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
1d1a3e0a
BG
1267 usec += client->start_delay;
1268 }
1269
a3fa4287
YW
1270 r = event_reset_time(client->event, &client->timeout_resend,
1271 clock_boottime_or_monotonic(),
1272 usec, 0,
1273 client_timeout_resend, client,
1274 client->event_priority, "dhcp4-resend-timer", true);
6a1cd41e
PF
1275 if (r < 0)
1276 client_stop(client, r);
1277
1278 return 0;
1279
1280}
1281
4b558378 1282static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) {
0af03ba5
TG
1283 client_initialize_io_events(client, io_callback);
1284 client_initialize_time_events(client);
1285
1286 return 0;
1287}
1288
1d1a3e0a 1289static int client_start_delayed(sd_dhcp_client *client) {
0f941add
PF
1290 int r;
1291
1292 assert_return(client, -EINVAL);
1293 assert_return(client->event, -EINVAL);
2f8e7633 1294 assert_return(client->ifindex > 0, -EINVAL);
0f941add
PF
1295 assert_return(client->fd < 0, -EBUSY);
1296 assert_return(client->xid == 0, -EINVAL);
a1140666 1297 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY);
0f941add
PF
1298
1299 client->xid = random_u32();
1300
2f8e7633 1301 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
76253e73 1302 client->xid, client->mac_addr,
9faed222 1303 client->mac_addr_len, client->arp_type, client->port);
0f941add
PF
1304 if (r < 0) {
1305 client_stop(client, r);
1306 return r;
1307 }
0f941add 1308 client->fd = r;
58ec2d3e 1309
3742095b 1310 if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT))
fa94c34b 1311 client->start_time = now(clock_boottime_or_monotonic());
0f941add 1312
0f941add
PF
1313 return client_initialize_events(client, client_receive_message_raw);
1314}
1315
1d1a3e0a
BG
1316static int client_start(sd_dhcp_client *client) {
1317 client->start_delay = 0;
1318 return client_start_delayed(client);
1319}
1320
4b558378 1321static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) {
751246ee 1322 sd_dhcp_client *client = userdata;
574cc928 1323 DHCP_CLIENT_DONT_DESTROY(client);
751246ee 1324
ee57a737
TG
1325 log_dhcp_client(client, "EXPIRED");
1326
03748142 1327 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
0f941add 1328
781ca7a1 1329 /* lease was lost, start over if not freed or stopped in callback */
574cc928 1330 if (client->state != DHCP_STATE_STOPPED) {
e5b04c8d
PF
1331 client_initialize(client);
1332 client_start(client);
1333 }
751246ee 1334
51debc1e
PF
1335 return 0;
1336}
1337
5ee482df 1338static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
3dd71400 1339 sd_dhcp_client *client = userdata;
574cc928 1340 DHCP_CLIENT_DONT_DESTROY(client);
3dd71400
PF
1341 int r;
1342
a1140666
LP
1343 assert(client);
1344
03e334a1 1345 client->receive_message = sd_event_source_unref(client->receive_message);
22fc2420 1346 client->fd = asynchronous_close(client->fd);
3dd71400
PF
1347
1348 client->state = DHCP_STATE_REBINDING;
11793fcd 1349 client->attempt = 0;
3dd71400 1350
2f8e7633 1351 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
76253e73 1352 client->xid, client->mac_addr,
9faed222
SS
1353 client->mac_addr_len, client->arp_type,
1354 client->port);
3dd71400
PF
1355 if (r < 0) {
1356 client_stop(client, r);
1357 return 0;
1358 }
3dd71400
PF
1359 client->fd = r;
1360
d23c45bf 1361 return client_initialize_events(client, client_receive_message_raw);
51debc1e
PF
1362}
1363
4b558378 1364static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
aba26854 1365 sd_dhcp_client *client = userdata;
574cc928 1366 DHCP_CLIENT_DONT_DESTROY(client);
aba26854
PF
1367
1368 client->state = DHCP_STATE_RENEWING;
11793fcd 1369 client->attempt = 0;
aba26854 1370
0af03ba5 1371 return client_initialize_time_events(client);
51debc1e
PF
1372}
1373
4b558378 1374static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) {
4afd3348 1375 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
5ee482df 1376 int r;
3e3d8f78 1377
a6cc569e
TG
1378 r = dhcp_lease_new(&lease);
1379 if (r < 0)
1380 return r;
8c00042c 1381
e37f74a6
DW
1382 if (client->client_id_len) {
1383 r = dhcp_lease_set_client_id(lease,
5bac5235 1384 (uint8_t *) &client->client_id,
e37f74a6
DW
1385 client->client_id_len);
1386 if (r < 0)
1387 return r;
1388 }
1389
f693e9b3 1390 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
9e64dd72 1391 if (r != DHCP_OFFER) {
6ff8806e 1392 log_dhcp_client(client, "received message was not an OFFER, ignoring");
5ee482df 1393 return -ENOMSG;
9e64dd72 1394 }
8c00042c 1395
8e34a618 1396 lease->next_server = offer->siaddr;
e5002702 1397 lease->address = offer->yiaddr;
8c00042c 1398
0339cd77
LP
1399 if (lease->address == 0 ||
1400 lease->server_address == 0 ||
9e64dd72 1401 lease->lifetime == 0) {
0339cd77 1402 log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring");
5ee482df 1403 return -ENOMSG;
9e64dd72
TG
1404 }
1405
0339cd77 1406 if (!lease->have_subnet_mask) {
9e64dd72
TG
1407 r = dhcp_lease_set_default_subnet_mask(lease);
1408 if (r < 0) {
87ac8d99
ZJS
1409 log_dhcp_client(client,
1410 "received lease lacks subnet mask, "
1411 "and a fallback one cannot be generated, ignoring");
9e64dd72
TG
1412 return -ENOMSG;
1413 }
1414 }
8c00042c 1415
6e00a806 1416 sd_dhcp_lease_unref(client->lease);
1cc6c93a 1417 client->lease = TAKE_PTR(lease);
8c00042c 1418
727b5734
SS
1419 if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
1420 return -ENOMSG;
1421
ee57a737
TG
1422 log_dhcp_client(client, "OFFER");
1423
8c00042c 1424 return 0;
8c00042c
PF
1425}
1426
4b558378 1427static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) {
615c1467
TG
1428 int r;
1429
f693e9b3 1430 r = dhcp_option_parse(force, len, NULL, NULL, NULL);
615c1467
TG
1431 if (r != DHCP_FORCERENEW)
1432 return -ENOMSG;
1433
1434 log_dhcp_client(client, "FORCERENEW");
1435
1436 return 0;
1437}
1438
3d9f6707
YW
1439static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) {
1440 if (a->address != b->address)
1441 return false;
1442
1443 if (a->subnet_mask != b->subnet_mask)
1444 return false;
1445
1446 if (a->router_size != b->router_size)
1447 return false;
1448
1449 for (size_t i = 0; i < a->router_size; i++)
1450 if (a->router[i].s_addr != b->router[i].s_addr)
1451 return false;
1452
1453 return true;
1454}
1455
4b558378 1456static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
4afd3348 1457 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
f693e9b3 1458 _cleanup_free_ char *error_message = NULL;
5ee482df 1459 int r;
3e3d8f78 1460
a6cc569e
TG
1461 r = dhcp_lease_new(&lease);
1462 if (r < 0)
1463 return r;
3e3d8f78 1464
e37f74a6
DW
1465 if (client->client_id_len) {
1466 r = dhcp_lease_set_client_id(lease,
5bac5235 1467 (uint8_t *) &client->client_id,
e37f74a6
DW
1468 client->client_id_len);
1469 if (r < 0)
1470 return r;
1471 }
1472
f693e9b3 1473 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
ee57a737 1474 if (r == DHCP_NAK) {
f693e9b3 1475 log_dhcp_client(client, "NAK: %s", strna(error_message));
2d2349cc 1476 return -EADDRNOTAVAIL;
ee57a737 1477 }
3e3d8f78 1478
9e64dd72 1479 if (r != DHCP_ACK) {
6ff8806e 1480 log_dhcp_client(client, "received message was not an ACK, ignoring");
5ee482df 1481 return -ENOMSG;
9e64dd72 1482 }
3e3d8f78 1483
8e34a618
TG
1484 lease->next_server = ack->siaddr;
1485
e5002702 1486 lease->address = ack->yiaddr;
3e3d8f78
PF
1487
1488 if (lease->address == INADDR_ANY ||
1489 lease->server_address == INADDR_ANY ||
9e64dd72 1490 lease->lifetime == 0) {
6ff8806e 1491 log_dhcp_client(client, "received lease lacks address, server "
9e64dd72 1492 "address or lease lifetime, ignoring");
5ee482df 1493 return -ENOMSG;
9e64dd72
TG
1494 }
1495
1496 if (lease->subnet_mask == INADDR_ANY) {
1497 r = dhcp_lease_set_default_subnet_mask(lease);
1498 if (r < 0) {
87ac8d99
ZJS
1499 log_dhcp_client(client,
1500 "received lease lacks subnet mask, "
1501 "and a fallback one cannot be generated, ignoring");
9e64dd72
TG
1502 return -ENOMSG;
1503 }
1504 }
3e3d8f78 1505
03748142 1506 r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
3e3d8f78 1507 if (client->lease) {
3d9f6707 1508 if (lease_equal(client->lease, lease))
03748142 1509 r = SD_DHCP_CLIENT_EVENT_RENEW;
3d9f6707
YW
1510 else
1511 r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
3e3d8f78 1512
a6cc569e 1513 client->lease = sd_dhcp_lease_unref(client->lease);
3e3d8f78
PF
1514 }
1515
1cc6c93a 1516 client->lease = TAKE_PTR(lease);
3e3d8f78 1517
ee57a737
TG
1518 log_dhcp_client(client, "ACK");
1519
3e3d8f78
PF
1520 return r;
1521}
1522
fbcd420a 1523static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) {
022446ad
TG
1524 assert(client);
1525 assert(client->request_sent);
fbcd420a 1526 assert(lifetime > 0);
022446ad 1527
fbcd420a
LP
1528 if (lifetime > 3)
1529 lifetime -= 3;
1530 else
1531 lifetime = 0;
1532
1533 return client->request_sent + (lifetime * USEC_PER_SEC * factor) +
9bf3b535 1534 + (random_u32() & 0x1fffff);
51debc1e
PF
1535}
1536
022446ad
TG
1537static int client_set_lease_timeouts(sd_dhcp_client *client) {
1538 usec_t time_now;
1539 uint64_t lifetime_timeout;
1540 uint64_t t2_timeout;
1541 uint64_t t1_timeout;
1542 char time_string[FORMAT_TIMESPAN_MAX];
5ee482df 1543 int r;
51debc1e 1544
b25ef18b
TG
1545 assert(client);
1546 assert(client->event);
022446ad
TG
1547 assert(client->lease);
1548 assert(client->lease->lifetime);
51debc1e 1549
022446ad 1550 /* don't set timers for infinite leases */
a3fa4287
YW
1551 if (client->lease->lifetime == 0xffffffff) {
1552 (void) event_source_disable(client->timeout_t1);
1553 (void) event_source_disable(client->timeout_t2);
1554 (void) event_source_disable(client->timeout_expire);
1555
022446ad 1556 return 0;
a3fa4287 1557 }
51debc1e 1558
fa94c34b 1559 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
022446ad
TG
1560 if (r < 0)
1561 return r;
1562 assert(client->request_sent <= time_now);
1563
1564 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1565 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
fbcd420a 1566 if (client->lease->t1 > 0 && client->lease->t2 > 0) {
022446ad
TG
1567 /* both T1 and T2 are given */
1568 if (client->lease->t1 < client->lease->t2 &&
1569 client->lease->t2 < client->lease->lifetime) {
1570 /* they are both valid */
1571 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1572 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1573 } else {
1574 /* discard both */
1575 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1576 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1577 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1578 client->lease->t1 = client->lease->lifetime / 2;
1579 }
fbcd420a 1580 } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) {
022446ad
TG
1581 /* only T2 is given, and it is valid */
1582 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1583 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1584 client->lease->t1 = client->lease->lifetime / 2;
1585 if (t2_timeout <= t1_timeout) {
1586 /* the computed T1 would be invalid, so discard T2 */
1587 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1588 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1589 }
fbcd420a 1590 } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) {
022446ad
TG
1591 /* only T1 is given, and it is valid */
1592 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1593 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1594 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1595 if (t2_timeout <= t1_timeout) {
1596 /* the computed T2 would be invalid, so discard T1 */
1597 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1598 client->lease->t2 = client->lease->lifetime / 2;
1599 }
1600 } else {
1601 /* fall back to the default timeouts */
1602 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1603 client->lease->t1 = client->lease->lifetime / 2;
1604 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1605 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1606 }
51debc1e 1607
022446ad 1608 /* arm lifetime timeout */
a3fa4287
YW
1609 r = event_reset_time(client->event, &client->timeout_expire,
1610 clock_boottime_or_monotonic(),
1611 lifetime_timeout, 10 * USEC_PER_MSEC,
1612 client_timeout_expire, client,
1613 client->event_priority, "dhcp4-lifetime", true);
9021bb9f
TG
1614 if (r < 0)
1615 return r;
1616
022446ad 1617 log_dhcp_client(client, "lease expires in %s",
ed19c567 1618 format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
51debc1e 1619
022446ad
TG
1620 /* don't arm earlier timeouts if this has already expired */
1621 if (lifetime_timeout <= time_now)
1622 return 0;
51debc1e 1623
022446ad 1624 /* arm T2 timeout */
a3fa4287
YW
1625 r = event_reset_time(client->event, &client->timeout_t2,
1626 clock_boottime_or_monotonic(),
1627 t2_timeout, 10 * USEC_PER_MSEC,
1628 client_timeout_t2, client,
1629 client->event_priority, "dhcp4-t2-timeout", true);
9021bb9f
TG
1630 if (r < 0)
1631 return r;
1632
022446ad 1633 log_dhcp_client(client, "T2 expires in %s",
ed19c567 1634 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
022446ad
TG
1635
1636 /* don't arm earlier timeout if this has already expired */
1637 if (t2_timeout <= time_now)
1638 return 0;
51debc1e 1639
022446ad 1640 /* arm T1 timeout */
a3fa4287
YW
1641 r = event_reset_time(client->event, &client->timeout_t1,
1642 clock_boottime_or_monotonic(),
1643 t1_timeout, 10 * USEC_PER_MSEC,
1644 client_timeout_t1, client,
1645 client->event_priority, "dhcp4-t1-timer", true);
9021bb9f
TG
1646 if (r < 0)
1647 return r;
1648
022446ad 1649 log_dhcp_client(client, "T1 expires in %s",
ed19c567 1650 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
022446ad 1651
51debc1e
PF
1652 return 0;
1653}
1654
4b558378 1655static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
574cc928 1656 DHCP_CLIENT_DONT_DESTROY(client);
1d1a3e0a 1657 char time_string[FORMAT_TIMESPAN_MAX];
e5002702 1658 int r = 0, notify_event = 0;
8c00042c 1659
b25ef18b
TG
1660 assert(client);
1661 assert(client->event);
e5002702 1662 assert(message);
b25ef18b 1663
8c00042c
PF
1664 switch (client->state) {
1665 case DHCP_STATE_SELECTING:
1666
e5002702
TG
1667 r = client_handle_offer(client, message, len);
1668 if (r >= 0) {
8c00042c 1669
8c00042c 1670 client->state = DHCP_STATE_REQUESTING;
11793fcd 1671 client->attempt = 0;
e2dfc79f 1672
a3fa4287
YW
1673 r = event_reset_time(client->event, &client->timeout_resend,
1674 clock_boottime_or_monotonic(),
1675 0, 0,
1676 client_timeout_resend, client,
1677 client->event_priority, "dhcp4-resend-timer", true);
9021bb9f
TG
1678 if (r < 0)
1679 goto error;
9e64dd72
TG
1680 } else if (r == -ENOMSG)
1681 /* invalid message, let's ignore it */
1682 return 0;
8c00042c
PF
1683
1684 break;
1685
8b1243f7 1686 case DHCP_STATE_REBOOTING:
3e3d8f78 1687 case DHCP_STATE_REQUESTING:
aba26854 1688 case DHCP_STATE_RENEWING:
3dd71400 1689 case DHCP_STATE_REBINDING:
aba26854 1690
e5002702 1691 r = client_handle_ack(client, message, len);
2d2349cc 1692 if (r >= 0) {
1d1a3e0a 1693 client->start_delay = 0;
a3fa4287 1694 (void) event_source_disable(client->timeout_resend);
affaa94f
DW
1695 client->receive_message =
1696 sd_event_source_unref(client->receive_message);
1697 client->fd = asynchronous_close(client->fd);
3e3d8f78 1698
8b1243f7
PF
1699 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1700 DHCP_STATE_REBOOTING))
03748142
DH
1701 notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1702 else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
aba26854
PF
1703 notify_event = r;
1704
3e3d8f78 1705 client->state = DHCP_STATE_BOUND;
11793fcd 1706 client->attempt = 0;
3e3d8f78
PF
1707
1708 client->last_addr = client->lease->address;
1709
022446ad 1710 r = client_set_lease_timeouts(client);
0411760a
TG
1711 if (r < 0) {
1712 log_dhcp_client(client, "could not set lease timeouts");
51debc1e 1713 goto error;
0411760a 1714 }
51debc1e 1715
afe42aef 1716 r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port, client->ip_service_type);
0af03ba5
TG
1717 if (r < 0) {
1718 log_dhcp_client(client, "could not bind UDP socket");
1719 goto error;
1720 }
1721
1722 client->fd = r;
1723
1724 client_initialize_io_events(client, client_receive_message_udp);
1725
e5b04c8d 1726 if (notify_event) {
574cc928
TG
1727 client_notify(client, notify_event);
1728 if (client->state == DHCP_STATE_STOPPED)
e5b04c8d
PF
1729 return 0;
1730 }
3e3d8f78 1731
2d2349cc
TG
1732 } else if (r == -EADDRNOTAVAIL) {
1733 /* got a NAK, let's restart the client */
cc3981b1
LS
1734 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
1735
2d2349cc
TG
1736 r = client_initialize(client);
1737 if (r < 0)
1738 goto error;
1739
1d1a3e0a 1740 r = client_start_delayed(client);
2d2349cc
TG
1741 if (r < 0)
1742 goto error;
1743
1d1a3e0a
BG
1744 log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1745 client->start_delay, USEC_PER_SEC));
1746
1747 client->start_delay = CLAMP(client->start_delay * 2,
1748 RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
2d2349cc
TG
1749
1750 return 0;
9e64dd72
TG
1751 } else if (r == -ENOMSG)
1752 /* invalid message, let's ignore it */
1753 return 0;
97b9372d 1754
3e3d8f78
PF
1755 break;
1756
615c1467
TG
1757 case DHCP_STATE_BOUND:
1758 r = client_handle_forcerenew(client, message, len);
1759 if (r >= 0) {
1760 r = client_timeout_t1(NULL, 0, client);
1761 if (r < 0)
1762 goto error;
1763 } else if (r == -ENOMSG)
1764 /* invalid message, let's ignore it */
1765 return 0;
1766
1767 break;
1768
8c00042c
PF
1769 case DHCP_STATE_INIT:
1770 case DHCP_STATE_INIT_REBOOT:
8c00042c
PF
1771
1772 break;
781ca7a1
PF
1773
1774 case DHCP_STATE_STOPPED:
1775 r = -EINVAL;
1776 goto error;
8c00042c
PF
1777 }
1778
1779error:
2d2349cc 1780 if (r < 0)
e5b04c8d 1781 client_stop(client, r);
e2dfc79f 1782
e5b04c8d 1783 return r;
8c00042c
PF
1784}
1785
4b558378
ZJS
1786static int client_receive_message_udp(
1787 sd_event_source *s,
1788 int fd,
1789 uint32_t revents,
1790 void *userdata) {
1791
e5002702 1792 sd_dhcp_client *client = userdata;
5266a81e 1793 _cleanup_free_ DHCPMessage *message = NULL;
13f1fd03 1794 const uint8_t *expected_chaddr = NULL;
76253e73 1795 uint8_t expected_hlen = 0;
4edc2c9b 1796 ssize_t len, buflen;
e5002702
TG
1797
1798 assert(s);
1799 assert(client);
e5002702 1800
4edc2c9b 1801 buflen = next_datagram_size_fd(fd);
22a3fd2d
BG
1802 if (buflen == -ENETDOWN) {
1803 /* the link is down. Don't return an error or the I/O event
1804 source will be disconnected and we won't be able to receive
1805 packets again when the link comes back. */
1806 return 0;
1807 }
4edc2c9b
LP
1808 if (buflen < 0)
1809 return buflen;
5266a81e
TG
1810
1811 message = malloc0(buflen);
1812 if (!message)
1813 return -ENOMEM;
1814
cf447cb6 1815 len = recv(fd, message, buflen, 0);
0c79c68d 1816 if (len < 0) {
22a3fd2d
BG
1817 /* see comment above for why we shouldn't error out on ENETDOWN. */
1818 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
0d43d2fc
TG
1819 return 0;
1820
25f027c5
ZJS
1821 return log_dhcp_client_errno(client, errno,
1822 "Could not receive message from UDP socket: %m");
004845d1
LP
1823 }
1824 if ((size_t) len < sizeof(DHCPMessage)) {
0d43d2fc 1825 log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
e5002702 1826 return 0;
9fbc2523
TG
1827 }
1828
1829 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
0d43d2fc 1830 log_dhcp_client(client, "Not a DHCP message: ignoring");
9fbc2523
TG
1831 return 0;
1832 }
1833
1834 if (message->op != BOOTREPLY) {
0d43d2fc 1835 log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
9fbc2523
TG
1836 return 0;
1837 }
1838
76253e73 1839 if (message->htype != client->arp_type) {
0d43d2fc 1840 log_dhcp_client(client, "Packet type does not match client type");
76253e73
DW
1841 return 0;
1842 }
1843
1844 if (client->arp_type == ARPHRD_ETHER) {
1845 expected_hlen = ETH_ALEN;
13f1fd03 1846 expected_chaddr = &client->mac_addr[0];
76253e73
DW
1847 }
1848
1849 if (message->hlen != expected_hlen) {
0d43d2fc 1850 log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
9fbc2523
TG
1851 return 0;
1852 }
1853
13f1fd03 1854 if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) {
0d43d2fc 1855 log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
9fbc2523
TG
1856 return 0;
1857 }
e5002702 1858
615c1467
TG
1859 if (client->state != DHCP_STATE_BOUND &&
1860 be32toh(message->xid) != client->xid) {
1861 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1862 so ignore the xid in this case */
0d43d2fc 1863 log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
615c1467
TG
1864 be32toh(message->xid), client->xid);
1865 return 0;
1866 }
1867
022446ad 1868 return client_handle_message(client, message, len);
e5002702
TG
1869}
1870
4b558378
ZJS
1871static int client_receive_message_raw(
1872 sd_event_source *s,
1873 int fd,
1874 uint32_t revents,
1875 void *userdata) {
1876
e5002702 1877 sd_dhcp_client *client = userdata;
5266a81e 1878 _cleanup_free_ DHCPPacket *packet = NULL;
55dab2ed
TG
1879 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1880 struct iovec iov = {};
1881 struct msghdr msg = {
1882 .msg_iov = &iov,
1883 .msg_iovlen = 1,
1884 .msg_control = cmsgbuf,
1885 .msg_controllen = sizeof(cmsgbuf),
1886 };
1887 struct cmsghdr *cmsg;
1888 bool checksum = true;
4edc2c9b
LP
1889 ssize_t buflen, len;
1890 int r;
e5002702
TG
1891
1892 assert(s);
1893 assert(client);
e5002702 1894
4edc2c9b 1895 buflen = next_datagram_size_fd(fd);
22a3fd2d
BG
1896 if (buflen == -ENETDOWN)
1897 return 0;
4edc2c9b
LP
1898 if (buflen < 0)
1899 return buflen;
5266a81e
TG
1900
1901 packet = malloc0(buflen);
1902 if (!packet)
1903 return -ENOMEM;
1904
cb310866 1905 iov = IOVEC_MAKE(packet, buflen);
55dab2ed 1906
a38d9945 1907 len = recvmsg(fd, &msg, 0);
55dab2ed 1908 if (len < 0) {
22a3fd2d 1909 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
0d43d2fc
TG
1910 return 0;
1911
25f027c5
ZJS
1912 return log_dhcp_client_errno(client, errno,
1913 "Could not receive message from raw socket: %m");
0c79c68d
TG
1914 } else if ((size_t)len < sizeof(DHCPPacket))
1915 return 0;
55dab2ed 1916
e4a0fe63 1917 CMSG_FOREACH(cmsg, &msg)
48a4612e
TG
1918 if (cmsg->cmsg_level == SOL_PACKET &&
1919 cmsg->cmsg_type == PACKET_AUXDATA &&
1920 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1921 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
55dab2ed
TG
1922
1923 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1924 break;
1925 }
e5002702 1926
9faed222 1927 r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
ac4f16ab 1928 if (r < 0)
9fadd4ca 1929 return 0;
e5002702
TG
1930
1931 len -= DHCP_IP_UDP_SIZE;
1932
022446ad 1933 return client_handle_message(client, &packet->dhcp, len);
e5002702
TG
1934}
1935
1c9a2e26
YW
1936int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
1937 assert_return(client, -EINVAL);
1938 assert_return(client->fd >= 0, -EINVAL);
1939
1940 client->start_delay = 0;
1941 client->attempt = 1;
1942 client->state = DHCP_STATE_RENEWING;
1943
1944 return client_initialize_time_events(client);
1945}
1946
5ee482df 1947int sd_dhcp_client_start(sd_dhcp_client *client) {
6a1cd41e 1948 int r;
d3d8ac2f 1949
46a66b79 1950 assert_return(client, -EINVAL);
46a66b79 1951
0f941add
PF
1952 r = client_initialize(client);
1953 if (r < 0)
6a1cd41e 1954 return r;
8c00042c 1955
66173db7 1956 /* RFC7844 section 3.3:
1957 SHOULD perform a complete four-way handshake, starting with a
1958 DHCPDISCOVER, to obtain a new address lease. If the client can
1959 ascertain that this is exactly the same network to which it was
1960 previously connected, and if the link-layer address did not change,
1961 the client MAY issue a DHCPREQUEST to try to reclaim the current
1962 address. */
1963 if (client->last_addr && !client->anonymize)
0f941add 1964 client->state = DHCP_STATE_INIT_REBOOT;
d3d8ac2f 1965
998d8047
TG
1966 r = client_start(client);
1967 if (r >= 0)
2f8e7633 1968 log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex);
998d8047
TG
1969
1970 return r;
46a66b79
PF
1971}
1972
1501b429
SS
1973int sd_dhcp_client_send_release(sd_dhcp_client *client) {
1974 assert_return(client, -EINVAL);
8ff4585f 1975 assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
8bea7e70 1976 assert_return(client->lease, -EUNATCH);
8ff4585f
ZJS
1977
1978 _cleanup_free_ DHCPPacket *release = NULL;
1979 size_t optoffset, optlen;
1980 int r;
1981
1982 r = client_message_init(client, &release, DHCP_RELEASE, &optlen, &optoffset);
1983 if (r < 0)
1984 return r;
1985
1986 /* Fill up release IP and MAC */
1987 release->dhcp.ciaddr = client->lease->address;
1988 memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
1501b429 1989
8ff4585f
ZJS
1990 r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
1991 SD_DHCP_OPTION_END, 0, NULL);
1992 if (r < 0)
1993 return r;
1994
1995 r = dhcp_network_send_udp_socket(client->fd,
1996 client->lease->server_address,
1997 DHCP_PORT_SERVER,
1998 &release->dhcp,
1999 sizeof(DHCPMessage) + optoffset);
2000 if (r < 0)
2001 return r;
2002
2003 log_dhcp_client(client, "RELEASE");
1501b429
SS
2004
2005 return 0;
2006}
2007
5ee482df 2008int sd_dhcp_client_stop(sd_dhcp_client *client) {
574cc928
TG
2009 DHCP_CLIENT_DONT_DESTROY(client);
2010
e5b04c8d
PF
2011 assert_return(client, -EINVAL);
2012
03748142 2013 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
574cc928 2014 client->state = DHCP_STATE_STOPPED;
e5b04c8d
PF
2015
2016 return 0;
bbdf06d9
PF
2017}
2018
32d20645 2019int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
b25ef18b
TG
2020 int r;
2021
2022 assert_return(client, -EINVAL);
2023 assert_return(!client->event, -EBUSY);
2024
2025 if (event)
2026 client->event = sd_event_ref(event);
2027 else {
2028 r = sd_event_default(&client->event);
2029 if (r < 0)
2030 return 0;
2031 }
2032
2033 client->event_priority = priority;
2034
2035 return 0;
2036}
2037
2038int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
2039 assert_return(client, -EINVAL);
2040
2041 client->event = sd_event_unref(client->event);
2042
2043 return 0;
2044}
2045
2046sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
a1140666 2047 assert_return(client, NULL);
b25ef18b
TG
2048
2049 return client->event;
2050}
2051
8301aa0b
YW
2052static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
2053 assert(client);
e5b04c8d 2054
3733eec3 2055 log_dhcp_client(client, "FREE");
6e00a806 2056
a3fa4287
YW
2057 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
2058 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
2059 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
2060 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
3733eec3 2061
a3fa4287 2062 client_initialize(client);
3733eec3
LP
2063
2064 sd_dhcp_client_detach_event(client);
2065
2066 sd_dhcp_lease_unref(client->lease);
2067
2068 free(client->req_opts);
2069 free(client->hostname);
2070 free(client->vendor_class_identifier);
af1c0de0 2071 client->user_class = strv_free(client->user_class);
cb29c156 2072 ordered_hashmap_free(client->options);
6b430fdb 2073 return mfree(client);
d2fe46b5
PF
2074}
2075
8301aa0b
YW
2076DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
2077
db3d2358 2078int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
4afd3348 2079 _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
011feef8 2080
b25ef18b 2081 assert_return(ret, -EINVAL);
d3d8ac2f 2082
be6bf4a7 2083 client = new(sd_dhcp_client, 1);
011feef8 2084 if (!client)
b25ef18b 2085 return -ENOMEM;
011feef8 2086
be6bf4a7
YW
2087 *client = (sd_dhcp_client) {
2088 .n_ref = 1,
2089 .state = DHCP_STATE_INIT,
2090 .ifindex = -1,
2091 .fd = -1,
be6bf4a7
YW
2092 .mtu = DHCP_DEFAULT_MIN_SIZE,
2093 .port = DHCP_PORT_CLIENT,
2094 .anonymize = !!anonymize,
715cedfb 2095 .max_attempts = (uint64_t) -1,
afe42aef 2096 .ip_service_type = -1,
be6bf4a7 2097 };
db3d2358 2098 /* NOTE: this could be moved to a function. */
2099 if (anonymize) {
2100 client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
2101 client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
2102 } else {
2103 client->req_opts_size = ELEMENTSOF(default_req_opts);
2104 client->req_opts = memdup(default_req_opts, client->req_opts_size);
2105 }
b25ef18b
TG
2106 if (!client->req_opts)
2107 return -ENOMEM;
2108
1cc6c93a 2109 *ret = TAKE_PTR(client);
011feef8 2110
b25ef18b 2111 return 0;
011feef8 2112}