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