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