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