]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-client.c
shared/install: use _cleanup_free_
[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
PF
57 int fd;
58 union sockaddr_union link;
59 sd_event_source *receive_message;
f5de5b00 60 bool request_broadcast;
011feef8 61 uint8_t *req_opts;
7a7c74ca 62 size_t req_opts_allocated;
011feef8 63 size_t req_opts_size;
3b349af6 64 be32_t last_addr;
76253e73
DW
65 uint8_t mac_addr[MAX_MAC_ADDR_LEN];
66 size_t mac_addr_len;
67 uint16_t arp_type;
5bac5235
TG
68 struct {
69 uint8_t type;
70 union {
71 struct {
72 /* 0: Generic (non-LL) (RFC 2132) */
73 uint8_t data[MAX_CLIENT_ID_LEN];
74 } _packed_ gen;
75 struct {
76 /* 1: Ethernet Link-Layer (RFC 2132) */
77 uint8_t haddr[ETH_ALEN];
78 } _packed_ eth;
79 struct {
80 /* 2 - 254: ARP/Link-Layer (RFC 2132) */
81 uint8_t haddr[0];
82 } _packed_ ll;
83 struct {
84 /* 255: Node-specific (RFC 4361) */
413708d1 85 be32_t iaid;
5bac5235
TG
86 struct duid duid;
87 } _packed_ ns;
88 struct {
89 uint8_t data[MAX_CLIENT_ID_LEN];
90 } _packed_ raw;
91 };
92 } _packed_ client_id;
ba6c0fd6 93 size_t client_id_len;
4cc7a82c 94 char *hostname;
edb85f0d 95 char *vendor_class_identifier;
324f8187 96 uint32_t mtu;
46a66b79 97 uint32_t xid;
d3d8ac2f 98 usec_t start_time;
e2dfc79f 99 unsigned int attempt;
51debc1e
PF
100 usec_t request_sent;
101 sd_event_source *timeout_t1;
102 sd_event_source *timeout_t2;
103 sd_event_source *timeout_expire;
45aa74c7 104 sd_dhcp_client_callback_t callback;
751246ee 105 void *userdata;
a6cc569e 106 sd_dhcp_lease *lease;
1d1a3e0a 107 usec_t start_delay;
011feef8
PF
108};
109
110static const uint8_t default_req_opts[] = {
22805d92
BG
111 SD_DHCP_OPTION_SUBNET_MASK,
112 SD_DHCP_OPTION_ROUTER,
113 SD_DHCP_OPTION_HOST_NAME,
114 SD_DHCP_OPTION_DOMAIN_NAME,
115 SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
011feef8
PF
116};
117
4b558378
ZJS
118static int client_receive_message_raw(
119 sd_event_source *s,
120 int fd,
121 uint32_t revents,
122 void *userdata);
123static int client_receive_message_udp(
124 sd_event_source *s,
125 int fd,
126 uint32_t revents,
127 void *userdata);
574cc928 128static void client_stop(sd_dhcp_client *client, int error);
aba26854 129
4b558378
ZJS
130int sd_dhcp_client_set_callback(
131 sd_dhcp_client *client,
132 sd_dhcp_client_callback_t cb,
133 void *userdata) {
45aa74c7 134
751246ee
PF
135 assert_return(client, -EINVAL);
136
45aa74c7 137 client->callback = cb;
751246ee
PF
138 client->userdata = userdata;
139
140 return 0;
141}
142
f5de5b00
TG
143int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
144 assert_return(client, -EINVAL);
145
146 client->request_broadcast = !!broadcast;
147
148 return 0;
149}
150
5ee482df 151int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
011feef8
PF
152 size_t i;
153
154 assert_return(client, -EINVAL);
a1140666 155 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
011feef8
PF
156
157 switch(option) {
a1140666 158
22805d92
BG
159 case SD_DHCP_OPTION_PAD:
160 case SD_DHCP_OPTION_OVERLOAD:
161 case SD_DHCP_OPTION_MESSAGE_TYPE:
162 case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
163 case SD_DHCP_OPTION_END:
011feef8
PF
164 return -EINVAL;
165
166 default:
167 break;
168 }
169
170 for (i = 0; i < client->req_opts_size; i++)
171 if (client->req_opts[i] == option)
172 return -EEXIST;
173
7a7c74ca 174 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
011feef8
PF
175 client->req_opts_size + 1))
176 return -ENOMEM;
177
7a7c74ca 178 client->req_opts[client->req_opts_size++] = option;
011feef8
PF
179
180 return 0;
181}
182
4b558378
ZJS
183int sd_dhcp_client_set_request_address(
184 sd_dhcp_client *client,
185 const struct in_addr *last_addr) {
a1140666 186
011feef8 187 assert_return(client, -EINVAL);
a1140666 188 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
011feef8
PF
189
190 if (last_addr)
191 client->last_addr = last_addr->s_addr;
192 else
193 client->last_addr = INADDR_ANY;
194
195 return 0;
196}
197
2f8e7633 198int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
011feef8 199
2f8e7633
LP
200 assert_return(client, -EINVAL);
201 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
202 assert_return(ifindex > 0, -EINVAL);
011feef8 203
2f8e7633 204 client->ifindex = ifindex;
011feef8
PF
205 return 0;
206}
207
4b558378
ZJS
208int sd_dhcp_client_set_mac(
209 sd_dhcp_client *client,
210 const uint8_t *addr,
211 size_t addr_len,
212 uint16_t arp_type) {
213
574cc928 214 DHCP_CLIENT_DONT_DESTROY(client);
4644fee0
TG
215 bool need_restart = false;
216
46a66b79 217 assert_return(client, -EINVAL);
4644fee0 218 assert_return(addr, -EINVAL);
76253e73
DW
219 assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
220 assert_return(arp_type > 0, -EINVAL);
221
222 if (arp_type == ARPHRD_ETHER)
223 assert_return(addr_len == ETH_ALEN, -EINVAL);
224 else if (arp_type == ARPHRD_INFINIBAND)
225 assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
226 else
227 return -EINVAL;
46a66b79 228
76253e73
DW
229 if (client->mac_addr_len == addr_len &&
230 memcmp(&client->mac_addr, addr, addr_len) == 0)
4644fee0
TG
231 return 0;
232
781ca7a1 233 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
a1140666 234 log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting");
4644fee0 235 need_restart = true;
03748142 236 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
4644fee0 237 }
02ec5cd7 238
76253e73
DW
239 memcpy(&client->mac_addr, addr, addr_len);
240 client->mac_addr_len = addr_len;
241 client->arp_type = arp_type;
242
ba6c0fd6
DW
243 if (need_restart && client->state != DHCP_STATE_STOPPED)
244 sd_dhcp_client_start(client);
245
246 return 0;
247}
248
4b558378
ZJS
249int sd_dhcp_client_get_client_id(
250 sd_dhcp_client *client,
251 uint8_t *type,
252 const uint8_t **data,
253 size_t *data_len) {
ba6c0fd6
DW
254
255 assert_return(client, -EINVAL);
256 assert_return(type, -EINVAL);
257 assert_return(data, -EINVAL);
258 assert_return(data_len, -EINVAL);
259
260 *type = 0;
261 *data = NULL;
262 *data_len = 0;
263 if (client->client_id_len) {
5bac5235 264 *type = client->client_id.type;
ba6c0fd6 265 *data = client->client_id.raw.data;
5bac5235 266 *data_len = client->client_id_len - sizeof(client->client_id.type);
ba6c0fd6
DW
267 }
268
269 return 0;
270}
271
4b558378
ZJS
272int sd_dhcp_client_set_client_id(
273 sd_dhcp_client *client,
274 uint8_t type,
275 const uint8_t *data,
276 size_t data_len) {
277
ba6c0fd6
DW
278 DHCP_CLIENT_DONT_DESTROY(client);
279 bool need_restart = false;
280
281 assert_return(client, -EINVAL);
282 assert_return(data, -EINVAL);
283 assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
284
285 switch (type) {
a1140666 286
ba6c0fd6
DW
287 case ARPHRD_ETHER:
288 if (data_len != ETH_ALEN)
289 return -EINVAL;
290 break;
a1140666 291
ba6c0fd6
DW
292 case ARPHRD_INFINIBAND:
293 if (data_len != INFINIBAND_ALEN)
294 return -EINVAL;
295 break;
a1140666 296
ba6c0fd6
DW
297 default:
298 break;
299 }
300
5bac5235
TG
301 if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
302 client->client_id.type == type &&
ba6c0fd6
DW
303 memcmp(&client->client_id.raw.data, data, data_len) == 0)
304 return 0;
305
306 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
307 log_dhcp_client(client, "Changing client ID on running DHCP "
308 "client, restarting");
309 need_restart = true;
03748142 310 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
ba6c0fd6
DW
311 }
312
5bac5235 313 client->client_id.type = type;
ba6c0fd6 314 memcpy(&client->client_id.raw.data, data, data_len);
5bac5235 315 client->client_id_len = data_len + sizeof (client->client_id.type);
46a66b79 316
781ca7a1 317 if (need_restart && client->state != DHCP_STATE_STOPPED)
4644fee0
TG
318 sd_dhcp_client_start(client);
319
46a66b79
PF
320 return 0;
321}
322
d7df2fd3
ZJS
323/**
324 * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
325 * without further modification. Otherwise, if duid_type is supported, DUID
326 * is set based on that type. Otherwise, an error is returned.
327 */
4b558378
ZJS
328int sd_dhcp_client_set_iaid_duid(
329 sd_dhcp_client *client,
330 uint32_t iaid,
331 uint16_t duid_type,
f7a92d1a 332 const void *duid,
4b558378
ZJS
333 size_t duid_len) {
334
413708d1
VK
335 DHCP_CLIENT_DONT_DESTROY(client);
336 int r;
d7df2fd3
ZJS
337 size_t len;
338
413708d1 339 assert_return(client, -EINVAL);
d7df2fd3
ZJS
340 assert_return(duid_len == 0 || duid != NULL, -EINVAL);
341
342 if (duid != NULL) {
343 r = dhcp_validate_duid_len(duid_type, duid_len);
344 if (r < 0)
345 return r;
346 }
413708d1 347
d7df2fd3 348 zero(client->client_id);
413708d1
VK
349 client->client_id.type = 255;
350
351 /* If IAID is not configured, generate it. */
352 if (iaid == 0) {
2f8e7633 353 r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
413708d1
VK
354 client->mac_addr_len,
355 &client->client_id.ns.iaid);
356 if (r < 0)
357 return r;
358 } else
359 client->client_id.ns.iaid = htobe32(iaid);
360
d7df2fd3 361 if (duid != NULL) {
413708d1
VK
362 client->client_id.ns.duid.type = htobe16(duid_type);
363 memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len);
d7df2fd3
ZJS
364 len = sizeof(client->client_id.ns.duid.type) + duid_len;
365 } else if (duid_type == DUID_TYPE_EN) {
366 r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
367 if (r < 0)
368 return r;
369 } else
370 return -EOPNOTSUPP;
413708d1 371
d7df2fd3 372 client->client_id_len = sizeof(client->client_id.type) + len +
413708d1
VK
373 sizeof(client->client_id.ns.iaid);
374
375 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
376 log_dhcp_client(client, "Configured IAID+DUID, restarting.");
377 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
378 sd_dhcp_client_start(client);
379 }
380
381 return 0;
382}
383
4b558378
ZJS
384int sd_dhcp_client_set_hostname(
385 sd_dhcp_client *client,
386 const char *hostname) {
387
4cc7a82c
EY
388 char *new_hostname = NULL;
389
390 assert_return(client, -EINVAL);
391
23873e25
BG
392 if (!hostname_is_valid(hostname, false) && !dns_name_is_valid(hostname))
393 return -EINVAL;
394
4cc7a82c
EY
395 if (streq_ptr(client->hostname, hostname))
396 return 0;
397
398 if (hostname) {
399 new_hostname = strdup(hostname);
400 if (!new_hostname)
401 return -ENOMEM;
402 }
403
404 free(client->hostname);
405 client->hostname = new_hostname;
406
407 return 0;
408}
409
4b558378
ZJS
410int sd_dhcp_client_set_vendor_class_identifier(
411 sd_dhcp_client *client,
412 const char *vci) {
413
edb85f0d
SS
414 char *new_vci = NULL;
415
416 assert_return(client, -EINVAL);
417
418 new_vci = strdup(vci);
419 if (!new_vci)
420 return -ENOMEM;
421
422 free(client->vendor_class_identifier);
423
424 client->vendor_class_identifier = new_vci;
425
426 return 0;
427}
428
324f8187
TG
429int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
430 assert_return(client, -EINVAL);
431 assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
432
433 client->mtu = mtu;
434
435 return 0;
436}
437
a6cc569e 438int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
751246ee 439 assert_return(client, -EINVAL);
751246ee 440
a6cc569e
TG
441 if (client->state != DHCP_STATE_BOUND &&
442 client->state != DHCP_STATE_RENEWING &&
443 client->state != DHCP_STATE_REBINDING)
444 return -EADDRNOTAVAIL;
751246ee 445
a1140666
LP
446 if (ret)
447 *ret = client->lease;
4f882b2a
TG
448
449 return 0;
450}
451
574cc928 452static void client_notify(sd_dhcp_client *client, int event) {
45aa74c7
LP
453 assert(client);
454
455 if (client->callback)
456 client->callback(client, event, client->userdata);
3e3d8f78
PF
457}
458
0f941add 459static int client_initialize(sd_dhcp_client *client) {
bbdf06d9 460 assert_return(client, -EINVAL);
bbdf06d9 461
a1140666 462 client->receive_message = sd_event_source_unref(client->receive_message);
8c00042c 463
22fc2420 464 client->fd = asynchronous_close(client->fd);
8c00042c 465
d3d8ac2f
PF
466 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
467
51debc1e
PF
468 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
469 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
470 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
471
e2dfc79f
PF
472 client->attempt = 1;
473
f8fdefe4 474 client->state = DHCP_STATE_INIT;
0f941add 475 client->xid = 0;
bbdf06d9 476
0339cd77 477 client->lease = sd_dhcp_lease_unref(client->lease);
8c00042c 478
0f941add
PF
479 return 0;
480}
481
574cc928
TG
482static void client_stop(sd_dhcp_client *client, int error) {
483 assert(client);
0f941add 484
ccfdc9a1
UTL
485 if (error < 0)
486 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
03748142 487 else if (error == SD_DHCP_CLIENT_EVENT_STOP)
2d2349cc
TG
488 log_dhcp_client(client, "STOPPED");
489 else
490 log_dhcp_client(client, "STOPPED: Unknown event");
0f941add 491
574cc928 492 client_notify(client, error);
ee57a737 493
574cc928 494 client_initialize(client);
bbdf06d9
PF
495}
496
4b558378
ZJS
497static int client_message_init(
498 sd_dhcp_client *client,
499 DHCPPacket **ret,
500 uint8_t type,
501 size_t *_optlen,
502 size_t *_optoffset) {
503
3587161a 504 _cleanup_free_ DHCPPacket *packet = NULL;
424a8732 505 size_t optlen, optoffset, size;
8a9e7616 506 be16_t max_size;
d8d74ef0
DW
507 usec_t time_now;
508 uint16_t secs;
cf597f65 509 int r;
46a66b79 510
6236f49b 511 assert(client);
d8d74ef0 512 assert(client->start_time);
424a8732
TG
513 assert(ret);
514 assert(_optlen);
515 assert(_optoffset);
8a9e7616 516 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
0a1b6da8 517
424a8732
TG
518 optlen = DHCP_MIN_OPTIONS_SIZE;
519 size = sizeof(DHCPPacket) + optlen;
520
521 packet = malloc0(size);
522 if (!packet)
523 return -ENOMEM;
524
525 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
76253e73 526 client->arp_type, optlen, &optoffset);
cf597f65
TG
527 if (r < 0)
528 return r;
46a66b79 529
0a1b6da8
TG
530 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
531 refuse to issue an DHCP lease if 'secs' is set to zero */
d8d74ef0
DW
532 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
533 if (r < 0)
534 return r;
535 assert(time_now >= client->start_time);
536
537 /* seconds between sending first and last DISCOVER
538 * must always be strictly positive to deal with broken servers */
539 secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
540 packet->dhcp.secs = htobe16(secs);
0a1b6da8 541
63a07041
CA
542 /* RFC2132 section 4.1
543 A client that cannot receive unicast IP datagrams until its protocol
544 software has been configured with an IP address SHOULD set the
545 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
546 DHCPREQUEST messages that client sends. The BROADCAST bit will
547 provide a hint to the DHCP server and BOOTP relay agent to broadcast
f5de5b00
TG
548 any messages to the client on the client's subnet.
549
550 Note: some interfaces needs this to be enabled, but some networks
551 needs this to be disabled as broadcasts are filteretd, so this
552 needs to be configurable */
76253e73 553 if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
f5de5b00 554 packet->dhcp.flags = htobe16(0x8000);
63a07041 555
50d6810e
TG
556 /* RFC2132 section 4.1.1:
557 The client MUST include its hardware address in the ’chaddr’ field, if
76253e73
DW
558 necessary for delivery of DHCP reply messages. Non-Ethernet
559 interfaces will leave 'chaddr' empty and use the client identifier
560 instead (eg, RFC 4390 section 2.1).
50d6810e 561 */
76253e73
DW
562 if (client->arp_type == ARPHRD_ETHER)
563 memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
f5a70de7 564
afec4539 565 /* If no client identifier exists, construct an RFC 4361-compliant one */
5bac5235
TG
566 if (client->client_id_len == 0) {
567 size_t duid_len;
568
569 client->client_id.type = 255;
570
2f8e7633 571 r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid);
5bac5235
TG
572 if (r < 0)
573 return r;
574
575 r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len);
576 if (r < 0)
577 return r;
578
579 client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
ba6c0fd6
DW
580 }
581
ee57a737 582 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
46a66b79 583 Identifier option is not set */
ba6c0fd6
DW
584 if (client->client_id_len) {
585 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
22805d92 586 SD_DHCP_OPTION_CLIENT_IDENTIFIER,
ba6c0fd6 587 client->client_id_len,
5bac5235 588 &client->client_id);
ba6c0fd6
DW
589 if (r < 0)
590 return r;
591 }
50d6810e
TG
592
593 /* RFC2131 section 3.5:
594 in its initial DHCPDISCOVER or DHCPREQUEST message, a
595 client may provide the server with a list of specific
596 parameters the client is interested in. If the client
597 includes a list of parameters in a DHCPDISCOVER message,
598 it MUST include that list in any subsequent DHCPREQUEST
599 messages.
600 */
424a8732 601 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
22805d92 602 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
20b958bf 603 client->req_opts_size, client->req_opts);
8a9e7616
TG
604 if (r < 0)
605 return r;
606
50d6810e
TG
607 /* RFC2131 section 3.5:
608 The client SHOULD include the ’maximum DHCP message size’ option to
609 let the server know how large the server may make its DHCP messages.
610
611 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
612 than the defined default size unless the Maximum Messge Size option
f131770b 613 is explicitly set
324f8187
TG
614
615 RFC3442 "Requirements to Avoid Sizing Constraints":
616 Because a full routing table can be quite large, the standard 576
617 octet maximum size for a DHCP message may be too short to contain
618 some legitimate Classless Static Route options. Because of this,
619 clients implementing the Classless Static Route option SHOULD send a
620 Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
621 stack is capable of receiving larger IP datagrams. In this case, the
622 client SHOULD set the value of this option to at least the MTU of the
623 interface that the client is configuring. The client MAY set the
624 value of this option higher, up to the size of the largest UDP packet
625 it is prepared to accept. (Note that the value specified in the
626 Maximum DHCP Message Size option is the total maximum packet size,
627 including IP and UDP headers.)
50d6810e 628 */
424a8732 629 max_size = htobe16(size);
324f8187 630 r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
22805d92 631 SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
8a9e7616
TG
632 2, &max_size);
633 if (r < 0)
634 return r;
46a66b79 635
424a8732
TG
636 *_optlen = optlen;
637 *_optoffset = optoffset;
638 *ret = packet;
639 packet = NULL;
640
46a66b79
PF
641 return 0;
642}
643
4b558378
ZJS
644static int client_append_fqdn_option(
645 DHCPMessage *message,
646 size_t optlen,
647 size_t *optoffset,
648 const char *fqdn) {
649
23873e25
BG
650 uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
651 int r;
652
653 buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
654 DHCP_FQDN_FLAG_E; /* Canonical wire format */
655 buffer[1] = 0; /* RCODE1 (deprecated) */
656 buffer[2] = 0; /* RCODE2 (deprecated) */
657
3cd03457 658 r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false);
23873e25
BG
659 if (r > 0)
660 r = dhcp_option_append(message, optlen, optoffset, 0,
22805d92 661 SD_DHCP_OPTION_FQDN, 3 + r, buffer);
23873e25
BG
662
663 return r;
664}
665
4b558378
ZJS
666static int dhcp_client_send_raw(
667 sd_dhcp_client *client,
668 DHCPPacket *packet,
669 size_t len) {
670
63edaa62
TG
671 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
672 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
673
674 return dhcp_network_send_raw_socket(client->fd, &client->link,
675 packet, len);
676}
677
6236f49b 678static int client_send_discover(sd_dhcp_client *client) {
9f2a50a3 679 _cleanup_free_ DHCPPacket *discover = NULL;
424a8732 680 size_t optoffset, optlen;
6236f49b
TG
681 int r;
682
683 assert(client);
50d6810e
TG
684 assert(client->state == DHCP_STATE_INIT ||
685 client->state == DHCP_STATE_SELECTING);
686
424a8732
TG
687 r = client_message_init(client, &discover, DHCP_DISCOVER,
688 &optlen, &optoffset);
6236f49b
TG
689 if (r < 0)
690 return r;
46a66b79 691
50d6810e
TG
692 /* the client may suggest values for the network address
693 and lease time in the DHCPDISCOVER message. The client may include
694 the ’requested IP address’ option to suggest that a particular IP
695 address be assigned, and may include the ’IP address lease time’
696 option to suggest the lease time it would like.
697 */
46a66b79 698 if (client->last_addr != INADDR_ANY) {
04b28be1 699 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 700 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
20b958bf 701 4, &client->last_addr);
6236f49b
TG
702 if (r < 0)
703 return r;
46a66b79
PF
704 }
705
4cc7a82c 706 if (client->hostname) {
23873e25
BG
707 /* According to RFC 4702 "clients that send the Client FQDN option in
708 their messages MUST NOT also send the Host Name option". Just send
709 one of the two depending on the hostname type.
710 */
dc477e73 711 if (dns_name_is_single_label(client->hostname)) {
23873e25
BG
712 /* it is unclear from RFC 2131 if client should send hostname in
713 DHCPDISCOVER but dhclient does and so we do as well
714 */
715 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 716 SD_DHCP_OPTION_HOST_NAME,
23873e25
BG
717 strlen(client->hostname), client->hostname);
718 } else
719 r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
720 client->hostname);
4cc7a82c
EY
721 if (r < 0)
722 return r;
723 }
724
edb85f0d
SS
725 if (client->vendor_class_identifier) {
726 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 727 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
edb85f0d
SS
728 strlen(client->vendor_class_identifier),
729 client->vendor_class_identifier);
730 if (r < 0)
731 return r;
732 }
733
04b28be1 734 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 735 SD_DHCP_OPTION_END, 0, NULL);
f7926298
TA
736 if (r < 0)
737 return r;
46a66b79 738
50d6810e
TG
739 /* We currently ignore:
740 The client SHOULD wait a random time between one and ten seconds to
741 desynchronize the use of DHCP at startup.
742 */
20b958bf 743 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
6236f49b
TG
744 if (r < 0)
745 return r;
e2dfc79f 746
ee57a737
TG
747 log_dhcp_client(client, "DISCOVER");
748
63edaa62 749 return 0;
e2dfc79f
PF
750}
751
6236f49b 752static int client_send_request(sd_dhcp_client *client) {
8186d9dd 753 _cleanup_free_ DHCPPacket *request = NULL;
424a8732 754 size_t optoffset, optlen;
6236f49b 755 int r;
e2dfc79f 756
a1140666
LP
757 assert(client);
758
759 r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset);
6236f49b
TG
760 if (r < 0)
761 return r;
46a66b79 762
8b1243f7 763 switch (client->state) {
50d6810e
TG
764 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
765 SELECTING should be REQUESTING)
766 */
767
768 case DHCP_STATE_REQUESTING:
769 /* Client inserts the address of the selected server in ’server
770 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
771 filled in with the yiaddr value from the chosen DHCPOFFER.
772 */
8b1243f7 773
04b28be1 774 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 775 SD_DHCP_OPTION_SERVER_IDENTIFIER,
50d6810e 776 4, &client->lease->server_address);
6236f49b
TG
777 if (r < 0)
778 return r;
8b1243f7 779
04b28be1 780 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 781 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
6236f49b
TG
782 4, &client->lease->address);
783 if (r < 0)
784 return r;
785
50d6810e
TG
786 break;
787
788 case DHCP_STATE_INIT_REBOOT:
789 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
790 option MUST be filled in with client’s notion of its previously
791 assigned address. ’ciaddr’ MUST be zero.
792 */
04b28be1 793 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 794 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
50d6810e 795 4, &client->last_addr);
6236f49b
TG
796 if (r < 0)
797 return r;
8b1243f7
PF
798 break;
799
8b1243f7 800 case DHCP_STATE_RENEWING:
50d6810e
TG
801 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
802 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
803 client’s IP address.
804 */
805
806 /* fall through */
8b1243f7 807 case DHCP_STATE_REBINDING:
50d6810e
TG
808 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
809 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
810 client’s IP address.
811
812 This message MUST be broadcast to the 0xffffffff IP broadcast address.
813 */
814 request->dhcp.ciaddr = client->lease->address;
8b1243f7
PF
815
816 break;
781ca7a1 817
50d6810e
TG
818 case DHCP_STATE_INIT:
819 case DHCP_STATE_SELECTING:
820 case DHCP_STATE_REBOOTING:
821 case DHCP_STATE_BOUND:
781ca7a1
PF
822 case DHCP_STATE_STOPPED:
823 return -EINVAL;
e2dfc79f 824 }
46a66b79 825
4cc7a82c 826 if (client->hostname) {
dc477e73 827 if (dns_name_is_single_label(client->hostname))
23873e25 828 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 829 SD_DHCP_OPTION_HOST_NAME,
23873e25
BG
830 strlen(client->hostname), client->hostname);
831 else
832 r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
833 client->hostname);
4cc7a82c
EY
834 if (r < 0)
835 return r;
836 }
837
04b28be1 838 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 839 SD_DHCP_OPTION_END, 0, NULL);
6236f49b
TG
840 if (r < 0)
841 return r;
46a66b79 842
aba26854 843 if (client->state == DHCP_STATE_RENEWING) {
6236f49b
TG
844 r = dhcp_network_send_udp_socket(client->fd,
845 client->lease->server_address,
846 DHCP_PORT_SERVER,
847 &request->dhcp,
20b958bf 848 sizeof(DHCPMessage) + optoffset);
aba26854 849 } else {
20b958bf 850 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
aba26854 851 }
6236f49b
TG
852 if (r < 0)
853 return r;
46a66b79 854
998d8047 855 switch (client->state) {
a1140666 856
998d8047
TG
857 case DHCP_STATE_REQUESTING:
858 log_dhcp_client(client, "REQUEST (requesting)");
859 break;
a1140666 860
998d8047
TG
861 case DHCP_STATE_INIT_REBOOT:
862 log_dhcp_client(client, "REQUEST (init-reboot)");
863 break;
a1140666 864
998d8047
TG
865 case DHCP_STATE_RENEWING:
866 log_dhcp_client(client, "REQUEST (renewing)");
867 break;
a1140666 868
998d8047
TG
869 case DHCP_STATE_REBINDING:
870 log_dhcp_client(client, "REQUEST (rebinding)");
871 break;
a1140666 872
998d8047
TG
873 default:
874 log_dhcp_client(client, "REQUEST (invalid)");
875 break;
876 }
ee57a737 877
63edaa62 878 return 0;
46a66b79
PF
879}
880
7739a40b
TG
881static int client_start(sd_dhcp_client *client);
882
4b558378
ZJS
883static int client_timeout_resend(
884 sd_event_source *s,
885 uint64_t usec,
886 void *userdata) {
887
d3d8ac2f 888 sd_dhcp_client *client = userdata;
574cc928 889 DHCP_CLIENT_DONT_DESTROY(client);
aba26854 890 usec_t next_timeout = 0;
d23c45bf 891 uint64_t time_now;
aba26854 892 uint32_t time_left;
d23c45bf 893 int r;
b25ef18b
TG
894
895 assert(s);
896 assert(client);
897 assert(client->event);
d3d8ac2f 898
fa94c34b 899 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
d23c45bf
TG
900 if (r < 0)
901 goto error;
902
aba26854 903 switch (client->state) {
a1140666 904
aba26854
PF
905 case DHCP_STATE_RENEWING:
906
e5002702 907 time_left = (client->lease->t2 - client->lease->t1) / 2;
aba26854
PF
908 if (time_left < 60)
909 time_left = 60;
d3d8ac2f 910
d23c45bf 911 next_timeout = time_now + time_left * USEC_PER_SEC;
d3d8ac2f 912
aba26854
PF
913 break;
914
3dd71400
PF
915 case DHCP_STATE_REBINDING:
916
e5002702 917 time_left = (client->lease->lifetime - client->lease->t2) / 2;
3dd71400
PF
918 if (time_left < 60)
919 time_left = 60;
920
d23c45bf 921 next_timeout = time_now + time_left * USEC_PER_SEC;
3dd71400
PF
922 break;
923
8b1243f7
PF
924 case DHCP_STATE_REBOOTING:
925 /* start over as we did not receive a timely ack or nak */
7739a40b 926 r = client_initialize(client);
eb105b96
TG
927 if (r < 0)
928 goto error;
8b1243f7 929
998d8047
TG
930 r = client_start(client);
931 if (r < 0)
932 goto error;
933 else {
934 log_dhcp_client(client, "REBOOTED");
935 return 0;
936 }
7739a40b 937
aba26854
PF
938 case DHCP_STATE_INIT:
939 case DHCP_STATE_INIT_REBOOT:
aba26854
PF
940 case DHCP_STATE_SELECTING:
941 case DHCP_STATE_REQUESTING:
942 case DHCP_STATE_BOUND:
aba26854
PF
943
944 if (client->attempt < 64)
945 client->attempt *= 2;
946
d23c45bf 947 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
aba26854
PF
948
949 break;
781ca7a1
PF
950
951 case DHCP_STATE_STOPPED:
952 r = -EINVAL;
953 goto error;
aba26854
PF
954 }
955
9bf3b535 956 next_timeout += (random_u32() & 0x1fffff);
d3d8ac2f 957
2333154a
UTL
958 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
959
6a0f1f6d
LP
960 r = sd_event_add_time(client->event,
961 &client->timeout_resend,
fa94c34b 962 clock_boottime_or_monotonic(),
6a0f1f6d
LP
963 next_timeout, 10 * USEC_PER_MSEC,
964 client_timeout_resend, client);
b25ef18b
TG
965 if (r < 0)
966 goto error;
967
e5002702
TG
968 r = sd_event_source_set_priority(client->timeout_resend,
969 client->event_priority);
b25ef18b 970 if (r < 0)
e2dfc79f 971 goto error;
d3d8ac2f 972
356779df 973 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
9021bb9f
TG
974 if (r < 0)
975 goto error;
976
e2dfc79f
PF
977 switch (client->state) {
978 case DHCP_STATE_INIT:
6236f49b 979 r = client_send_discover(client);
b25ef18b 980 if (r >= 0) {
e2dfc79f
PF
981 client->state = DHCP_STATE_SELECTING;
982 client->attempt = 1;
983 } else {
984 if (client->attempt >= 64)
985 goto error;
986 }
987
988 break;
989
990 case DHCP_STATE_SELECTING:
6236f49b 991 r = client_send_discover(client);
b25ef18b 992 if (r < 0 && client->attempt >= 64)
d3d8ac2f
PF
993 goto error;
994
e2dfc79f
PF
995 break;
996
8b1243f7 997 case DHCP_STATE_INIT_REBOOT:
e2dfc79f 998 case DHCP_STATE_REQUESTING:
aba26854 999 case DHCP_STATE_RENEWING:
3dd71400 1000 case DHCP_STATE_REBINDING:
6236f49b 1001 r = client_send_request(client);
b25ef18b 1002 if (r < 0 && client->attempt >= 64)
e2dfc79f 1003 goto error;
d3d8ac2f 1004
8b1243f7
PF
1005 if (client->state == DHCP_STATE_INIT_REBOOT)
1006 client->state = DHCP_STATE_REBOOTING;
1007
d23c45bf 1008 client->request_sent = time_now;
51debc1e 1009
d3d8ac2f
PF
1010 break;
1011
d3d8ac2f 1012 case DHCP_STATE_REBOOTING:
d3d8ac2f 1013 case DHCP_STATE_BOUND:
d3d8ac2f
PF
1014
1015 break;
781ca7a1
PF
1016
1017 case DHCP_STATE_STOPPED:
1018 r = -EINVAL;
1019 goto error;
d3d8ac2f
PF
1020 }
1021
1022 return 0;
1023
1024error:
b25ef18b 1025 client_stop(client, r);
d3d8ac2f
PF
1026
1027 /* Errors were dealt with when stopping the client, don't spill
1028 errors into the event loop handler */
1029 return 0;
1030}
1031
4b558378
ZJS
1032static int client_initialize_io_events(
1033 sd_dhcp_client *client,
1034 sd_event_io_handler_t io_callback) {
1035
6a1cd41e
PF
1036 int r;
1037
b25ef18b
TG
1038 assert(client);
1039 assert(client->event);
1040
151b9b96
LP
1041 r = sd_event_add_io(client->event, &client->receive_message,
1042 client->fd, EPOLLIN, io_callback,
1043 client);
6a1cd41e
PF
1044 if (r < 0)
1045 goto error;
1046
e5002702
TG
1047 r = sd_event_source_set_priority(client->receive_message,
1048 client->event_priority);
b25ef18b
TG
1049 if (r < 0)
1050 goto error;
1051
356779df 1052 r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
9021bb9f
TG
1053 if (r < 0)
1054 goto error;
1055
0af03ba5
TG
1056error:
1057 if (r < 0)
1058 client_stop(client, r);
1059
1060 return 0;
1061}
1062
1063static int client_initialize_time_events(sd_dhcp_client *client) {
1d1a3e0a 1064 uint64_t usec = 0;
0af03ba5
TG
1065 int r;
1066
1067 assert(client);
1068 assert(client->event);
1069
2333154a
UTL
1070 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
1071
1d1a3e0a 1072 if (client->start_delay) {
8ecdcb55 1073 assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
1d1a3e0a
BG
1074 usec += client->start_delay;
1075 }
1076
6a0f1f6d
LP
1077 r = sd_event_add_time(client->event,
1078 &client->timeout_resend,
fa94c34b 1079 clock_boottime_or_monotonic(),
1d1a3e0a 1080 usec, 0,
6a0f1f6d 1081 client_timeout_resend, client);
b25ef18b
TG
1082 if (r < 0)
1083 goto error;
1084
e5002702
TG
1085 r = sd_event_source_set_priority(client->timeout_resend,
1086 client->event_priority);
144c3488
TA
1087 if (r < 0)
1088 goto error;
6a1cd41e 1089
356779df 1090 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
9021bb9f
TG
1091 if (r < 0)
1092 goto error;
1093
6a1cd41e
PF
1094error:
1095 if (r < 0)
1096 client_stop(client, r);
1097
1098 return 0;
1099
1100}
1101
4b558378 1102static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) {
0af03ba5
TG
1103 client_initialize_io_events(client, io_callback);
1104 client_initialize_time_events(client);
1105
1106 return 0;
1107}
1108
1d1a3e0a 1109static int client_start_delayed(sd_dhcp_client *client) {
0f941add
PF
1110 int r;
1111
1112 assert_return(client, -EINVAL);
1113 assert_return(client->event, -EINVAL);
2f8e7633 1114 assert_return(client->ifindex > 0, -EINVAL);
0f941add
PF
1115 assert_return(client->fd < 0, -EBUSY);
1116 assert_return(client->xid == 0, -EINVAL);
a1140666 1117 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY);
0f941add
PF
1118
1119 client->xid = random_u32();
1120
2f8e7633 1121 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
76253e73
DW
1122 client->xid, client->mac_addr,
1123 client->mac_addr_len, client->arp_type);
0f941add
PF
1124 if (r < 0) {
1125 client_stop(client, r);
1126 return r;
1127 }
0f941add 1128 client->fd = r;
58ec2d3e 1129
d8d74ef0 1130 if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT)
fa94c34b 1131 client->start_time = now(clock_boottime_or_monotonic());
0f941add 1132
0f941add
PF
1133 return client_initialize_events(client, client_receive_message_raw);
1134}
1135
1d1a3e0a
BG
1136static int client_start(sd_dhcp_client *client) {
1137 client->start_delay = 0;
1138 return client_start_delayed(client);
1139}
1140
4b558378 1141static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) {
751246ee 1142 sd_dhcp_client *client = userdata;
574cc928 1143 DHCP_CLIENT_DONT_DESTROY(client);
751246ee 1144
ee57a737
TG
1145 log_dhcp_client(client, "EXPIRED");
1146
03748142 1147 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
0f941add 1148
781ca7a1 1149 /* lease was lost, start over if not freed or stopped in callback */
574cc928 1150 if (client->state != DHCP_STATE_STOPPED) {
e5b04c8d
PF
1151 client_initialize(client);
1152 client_start(client);
1153 }
751246ee 1154
51debc1e
PF
1155 return 0;
1156}
1157
5ee482df 1158static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
3dd71400 1159 sd_dhcp_client *client = userdata;
574cc928 1160 DHCP_CLIENT_DONT_DESTROY(client);
3dd71400
PF
1161 int r;
1162
a1140666
LP
1163 assert(client);
1164
03e334a1 1165 client->receive_message = sd_event_source_unref(client->receive_message);
22fc2420 1166 client->fd = asynchronous_close(client->fd);
3dd71400
PF
1167
1168 client->state = DHCP_STATE_REBINDING;
1169 client->attempt = 1;
1170
2f8e7633 1171 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
76253e73
DW
1172 client->xid, client->mac_addr,
1173 client->mac_addr_len, client->arp_type);
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
0af03ba5
TG
1558 r = dhcp_network_bind_udp_socket(client->lease->address,
1559 DHCP_PORT_CLIENT);
1560 if (r < 0) {
1561 log_dhcp_client(client, "could not bind UDP socket");
1562 goto error;
1563 }
1564
1565 client->fd = r;
1566
1567 client_initialize_io_events(client, client_receive_message_udp);
1568
e5b04c8d 1569 if (notify_event) {
574cc928
TG
1570 client_notify(client, notify_event);
1571 if (client->state == DHCP_STATE_STOPPED)
e5b04c8d
PF
1572 return 0;
1573 }
3e3d8f78 1574
2d2349cc
TG
1575 } else if (r == -EADDRNOTAVAIL) {
1576 /* got a NAK, let's restart the client */
1577 client->timeout_resend =
1578 sd_event_source_unref(client->timeout_resend);
1579
1580 r = client_initialize(client);
1581 if (r < 0)
1582 goto error;
1583
1d1a3e0a 1584 r = client_start_delayed(client);
2d2349cc
TG
1585 if (r < 0)
1586 goto error;
1587
1d1a3e0a
BG
1588 log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1589 client->start_delay, USEC_PER_SEC));
1590
1591 client->start_delay = CLAMP(client->start_delay * 2,
1592 RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
2d2349cc
TG
1593
1594 return 0;
9e64dd72
TG
1595 } else if (r == -ENOMSG)
1596 /* invalid message, let's ignore it */
1597 return 0;
97b9372d 1598
3e3d8f78
PF
1599 break;
1600
615c1467
TG
1601 case DHCP_STATE_BOUND:
1602 r = client_handle_forcerenew(client, message, len);
1603 if (r >= 0) {
1604 r = client_timeout_t1(NULL, 0, client);
1605 if (r < 0)
1606 goto error;
1607 } else if (r == -ENOMSG)
1608 /* invalid message, let's ignore it */
1609 return 0;
1610
1611 break;
1612
8c00042c
PF
1613 case DHCP_STATE_INIT:
1614 case DHCP_STATE_INIT_REBOOT:
8c00042c
PF
1615
1616 break;
781ca7a1
PF
1617
1618 case DHCP_STATE_STOPPED:
1619 r = -EINVAL;
1620 goto error;
8c00042c
PF
1621 }
1622
1623error:
2d2349cc 1624 if (r < 0)
e5b04c8d 1625 client_stop(client, r);
e2dfc79f 1626
e5b04c8d 1627 return r;
8c00042c
PF
1628}
1629
4b558378
ZJS
1630static int client_receive_message_udp(
1631 sd_event_source *s,
1632 int fd,
1633 uint32_t revents,
1634 void *userdata) {
1635
e5002702 1636 sd_dhcp_client *client = userdata;
5266a81e 1637 _cleanup_free_ DHCPMessage *message = NULL;
16f0b479 1638 const struct ether_addr zero_mac = {};
3dc05554 1639 const struct ether_addr *expected_chaddr = NULL;
76253e73 1640 uint8_t expected_hlen = 0;
4edc2c9b 1641 ssize_t len, buflen;
e5002702
TG
1642
1643 assert(s);
1644 assert(client);
e5002702 1645
4edc2c9b
LP
1646 buflen = next_datagram_size_fd(fd);
1647 if (buflen < 0)
1648 return buflen;
5266a81e
TG
1649
1650 message = malloc0(buflen);
1651 if (!message)
1652 return -ENOMEM;
1653
cf447cb6 1654 len = recv(fd, message, buflen, 0);
0c79c68d 1655 if (len < 0) {
0d43d2fc
TG
1656 if (errno == EAGAIN || errno == EINTR)
1657 return 0;
1658
004845d1
LP
1659 return log_dhcp_client_errno(client, errno, "Could not receive message from UDP socket: %m");
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
1752 log_dhcp_client(client, "Could not receive message from raw socket: %m");
1753
1754 return -errno;
0c79c68d
TG
1755 } else if ((size_t)len < sizeof(DHCPPacket))
1756 return 0;
55dab2ed 1757
2a1288ff 1758 CMSG_FOREACH(cmsg, &msg) {
48a4612e
TG
1759 if (cmsg->cmsg_level == SOL_PACKET &&
1760 cmsg->cmsg_type == PACKET_AUXDATA &&
1761 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1762 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
55dab2ed
TG
1763
1764 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1765 break;
1766 }
1767 }
e5002702 1768
55dab2ed 1769 r = dhcp_packet_verify_headers(packet, len, checksum);
ac4f16ab 1770 if (r < 0)
9fadd4ca 1771 return 0;
e5002702
TG
1772
1773 len -= DHCP_IP_UDP_SIZE;
1774
022446ad 1775 return client_handle_message(client, &packet->dhcp, len);
e5002702
TG
1776}
1777
5ee482df 1778int sd_dhcp_client_start(sd_dhcp_client *client) {
6a1cd41e 1779 int r;
d3d8ac2f 1780
46a66b79 1781 assert_return(client, -EINVAL);
46a66b79 1782
0f941add
PF
1783 r = client_initialize(client);
1784 if (r < 0)
6a1cd41e 1785 return r;
8c00042c 1786
0f941add
PF
1787 if (client->last_addr)
1788 client->state = DHCP_STATE_INIT_REBOOT;
d3d8ac2f 1789
998d8047
TG
1790 r = client_start(client);
1791 if (r >= 0)
2f8e7633 1792 log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex);
998d8047
TG
1793
1794 return r;
46a66b79
PF
1795}
1796
5ee482df 1797int sd_dhcp_client_stop(sd_dhcp_client *client) {
574cc928
TG
1798 DHCP_CLIENT_DONT_DESTROY(client);
1799
e5b04c8d
PF
1800 assert_return(client, -EINVAL);
1801
03748142 1802 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
574cc928 1803 client->state = DHCP_STATE_STOPPED;
e5b04c8d
PF
1804
1805 return 0;
bbdf06d9
PF
1806}
1807
32d20645 1808int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
b25ef18b
TG
1809 int r;
1810
1811 assert_return(client, -EINVAL);
1812 assert_return(!client->event, -EBUSY);
1813
1814 if (event)
1815 client->event = sd_event_ref(event);
1816 else {
1817 r = sd_event_default(&client->event);
1818 if (r < 0)
1819 return 0;
1820 }
1821
1822 client->event_priority = priority;
1823
1824 return 0;
1825}
1826
1827int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1828 assert_return(client, -EINVAL);
1829
1830 client->event = sd_event_unref(client->event);
1831
1832 return 0;
1833}
1834
1835sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
a1140666 1836 assert_return(client, NULL);
b25ef18b
TG
1837
1838 return client->event;
1839}
1840
e5b04c8d 1841sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
3733eec3
LP
1842
1843 if (!client)
1844 return NULL;
1845
1846 assert(client->n_ref >= 1);
1847 client->n_ref++;
e5b04c8d
PF
1848
1849 return client;
1850}
1851
1852sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
d2fe46b5 1853
3733eec3
LP
1854 if (!client)
1855 return NULL;
e5b04c8d 1856
3733eec3
LP
1857 assert(client->n_ref >= 1);
1858 client->n_ref--;
e5b04c8d 1859
3733eec3
LP
1860 if (client->n_ref > 0)
1861 return NULL;
e5b04c8d 1862
3733eec3 1863 log_dhcp_client(client, "FREE");
6e00a806 1864
3733eec3
LP
1865 client_initialize(client);
1866
1867 client->receive_message = sd_event_source_unref(client->receive_message);
1868
1869 sd_dhcp_client_detach_event(client);
1870
1871 sd_dhcp_lease_unref(client->lease);
1872
1873 free(client->req_opts);
1874 free(client->hostname);
1875 free(client->vendor_class_identifier);
1876 free(client);
d2fe46b5 1877
574cc928 1878 return NULL;
d2fe46b5
PF
1879}
1880
b25ef18b 1881int sd_dhcp_client_new(sd_dhcp_client **ret) {
4afd3348 1882 _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
011feef8 1883
b25ef18b 1884 assert_return(ret, -EINVAL);
d3d8ac2f 1885
011feef8
PF
1886 client = new0(sd_dhcp_client, 1);
1887 if (!client)
b25ef18b 1888 return -ENOMEM;
011feef8 1889
3733eec3 1890 client->n_ref = 1;
011feef8 1891 client->state = DHCP_STATE_INIT;
2f8e7633 1892 client->ifindex = -1;
8c00042c 1893 client->fd = -1;
e2dfc79f 1894 client->attempt = 1;
324f8187 1895 client->mtu = DHCP_DEFAULT_MIN_SIZE;
011feef8
PF
1896
1897 client->req_opts_size = ELEMENTSOF(default_req_opts);
011feef8 1898 client->req_opts = memdup(default_req_opts, client->req_opts_size);
b25ef18b
TG
1899 if (!client->req_opts)
1900 return -ENOMEM;
1901
1902 *ret = client;
1903 client = NULL;
011feef8 1904
b25ef18b 1905 return 0;
011feef8 1906}