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