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