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