]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-client.c
dns-domain: simplify dns_name_is_root() and dns_name_is_single_label()
[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) {
a6cc569e 1070 _cleanup_dhcp_lease_unref_ 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
e5002702 1085 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
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
1124 r = dhcp_option_parse(force, len, NULL, NULL);
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) {
a6cc569e 1135 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
5ee482df 1136 int r;
3e3d8f78 1137
a6cc569e
TG
1138 r = dhcp_lease_new(&lease);
1139 if (r < 0)
1140 return r;
3e3d8f78 1141
e37f74a6
DW
1142 if (client->client_id_len) {
1143 r = dhcp_lease_set_client_id(lease,
5bac5235 1144 (uint8_t *) &client->client_id,
e37f74a6
DW
1145 client->client_id_len);
1146 if (r < 0)
1147 return r;
1148 }
1149
e5002702 1150 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
ee57a737
TG
1151 if (r == DHCP_NAK) {
1152 log_dhcp_client(client, "NAK");
2d2349cc 1153 return -EADDRNOTAVAIL;
ee57a737 1154 }
3e3d8f78 1155
9e64dd72 1156 if (r != DHCP_ACK) {
6ff8806e 1157 log_dhcp_client(client, "received message was not an ACK, ignoring");
5ee482df 1158 return -ENOMSG;
9e64dd72 1159 }
3e3d8f78 1160
8e34a618
TG
1161 lease->next_server = ack->siaddr;
1162
e5002702 1163 lease->address = ack->yiaddr;
3e3d8f78
PF
1164
1165 if (lease->address == INADDR_ANY ||
1166 lease->server_address == INADDR_ANY ||
9e64dd72 1167 lease->lifetime == 0) {
6ff8806e 1168 log_dhcp_client(client, "received lease lacks address, server "
9e64dd72 1169 "address or lease lifetime, ignoring");
5ee482df 1170 return -ENOMSG;
9e64dd72
TG
1171 }
1172
1173 if (lease->subnet_mask == INADDR_ANY) {
1174 r = dhcp_lease_set_default_subnet_mask(lease);
1175 if (r < 0) {
6ff8806e 1176 log_dhcp_client(client, "received lease lacks subnet "
9e64dd72
TG
1177 "mask, and a fallback one can not be "
1178 "generated, ignoring");
1179 return -ENOMSG;
1180 }
1181 }
3e3d8f78 1182
03748142 1183 r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
3e3d8f78
PF
1184 if (client->lease) {
1185 if (client->lease->address != lease->address ||
1186 client->lease->subnet_mask != lease->subnet_mask ||
1187 client->lease->router != lease->router) {
03748142 1188 r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
68ceb9df 1189 } else
03748142 1190 r = SD_DHCP_CLIENT_EVENT_RENEW;
3e3d8f78 1191
a6cc569e 1192 client->lease = sd_dhcp_lease_unref(client->lease);
3e3d8f78
PF
1193 }
1194
1195 client->lease = lease;
5ee482df 1196 lease = NULL;
3e3d8f78 1197
ee57a737
TG
1198 log_dhcp_client(client, "ACK");
1199
3e3d8f78
PF
1200 return r;
1201}
1202
fbcd420a 1203static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) {
022446ad
TG
1204 assert(client);
1205 assert(client->request_sent);
fbcd420a 1206 assert(lifetime > 0);
022446ad 1207
fbcd420a
LP
1208 if (lifetime > 3)
1209 lifetime -= 3;
1210 else
1211 lifetime = 0;
1212
1213 return client->request_sent + (lifetime * USEC_PER_SEC * factor) +
9bf3b535 1214 + (random_u32() & 0x1fffff);
51debc1e
PF
1215}
1216
022446ad
TG
1217static int client_set_lease_timeouts(sd_dhcp_client *client) {
1218 usec_t time_now;
1219 uint64_t lifetime_timeout;
1220 uint64_t t2_timeout;
1221 uint64_t t1_timeout;
1222 char time_string[FORMAT_TIMESPAN_MAX];
5ee482df 1223 int r;
51debc1e 1224
b25ef18b
TG
1225 assert(client);
1226 assert(client->event);
022446ad
TG
1227 assert(client->lease);
1228 assert(client->lease->lifetime);
51debc1e 1229
aba26854
PF
1230 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1231 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1232 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
1233
022446ad
TG
1234 /* don't set timers for infinite leases */
1235 if (client->lease->lifetime == 0xffffffff)
1236 return 0;
51debc1e 1237
fa94c34b 1238 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
022446ad
TG
1239 if (r < 0)
1240 return r;
1241 assert(client->request_sent <= time_now);
1242
1243 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1244 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
fbcd420a 1245 if (client->lease->t1 > 0 && client->lease->t2 > 0) {
022446ad
TG
1246 /* both T1 and T2 are given */
1247 if (client->lease->t1 < client->lease->t2 &&
1248 client->lease->t2 < client->lease->lifetime) {
1249 /* they are both valid */
1250 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1251 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1252 } else {
1253 /* discard both */
1254 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1255 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1256 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1257 client->lease->t1 = client->lease->lifetime / 2;
1258 }
fbcd420a 1259 } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) {
022446ad
TG
1260 /* only T2 is given, and it is valid */
1261 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1262 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1263 client->lease->t1 = client->lease->lifetime / 2;
1264 if (t2_timeout <= t1_timeout) {
1265 /* the computed T1 would be invalid, so discard T2 */
1266 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1267 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1268 }
fbcd420a 1269 } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) {
022446ad
TG
1270 /* only T1 is given, and it is valid */
1271 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1272 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1273 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1274 if (t2_timeout <= t1_timeout) {
1275 /* the computed T2 would be invalid, so discard T1 */
1276 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1277 client->lease->t2 = client->lease->lifetime / 2;
1278 }
1279 } else {
1280 /* fall back to the default timeouts */
1281 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1282 client->lease->t1 = client->lease->lifetime / 2;
1283 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1284 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1285 }
51debc1e 1286
022446ad 1287 /* arm lifetime timeout */
6a0f1f6d 1288 r = sd_event_add_time(client->event, &client->timeout_expire,
fa94c34b 1289 clock_boottime_or_monotonic(),
6a0f1f6d
LP
1290 lifetime_timeout, 10 * USEC_PER_MSEC,
1291 client_timeout_expire, client);
5ee482df
TG
1292 if (r < 0)
1293 return r;
51debc1e 1294
022446ad 1295 r = sd_event_source_set_priority(client->timeout_expire,
e5002702 1296 client->event_priority);
b25ef18b
TG
1297 if (r < 0)
1298 return r;
1299
356779df 1300 r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime");
9021bb9f
TG
1301 if (r < 0)
1302 return r;
1303
022446ad 1304 log_dhcp_client(client, "lease expires in %s",
ed19c567 1305 format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
51debc1e 1306
022446ad
TG
1307 /* don't arm earlier timeouts if this has already expired */
1308 if (lifetime_timeout <= time_now)
1309 return 0;
51debc1e 1310
022446ad 1311 /* arm T2 timeout */
6a0f1f6d
LP
1312 r = sd_event_add_time(client->event,
1313 &client->timeout_t2,
fa94c34b 1314 clock_boottime_or_monotonic(),
6a0f1f6d
LP
1315 t2_timeout,
1316 10 * USEC_PER_MSEC,
1317 client_timeout_t2, client);
5ee482df
TG
1318 if (r < 0)
1319 return r;
51debc1e 1320
e5002702
TG
1321 r = sd_event_source_set_priority(client->timeout_t2,
1322 client->event_priority);
b25ef18b
TG
1323 if (r < 0)
1324 return r;
1325
356779df 1326 r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout");
9021bb9f
TG
1327 if (r < 0)
1328 return r;
1329
022446ad 1330 log_dhcp_client(client, "T2 expires in %s",
ed19c567 1331 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
022446ad
TG
1332
1333 /* don't arm earlier timeout if this has already expired */
1334 if (t2_timeout <= time_now)
1335 return 0;
51debc1e 1336
022446ad 1337 /* arm T1 timeout */
6a0f1f6d
LP
1338 r = sd_event_add_time(client->event,
1339 &client->timeout_t1,
fa94c34b 1340 clock_boottime_or_monotonic(),
6a0f1f6d
LP
1341 t1_timeout, 10 * USEC_PER_MSEC,
1342 client_timeout_t1, client);
5ee482df
TG
1343 if (r < 0)
1344 return r;
51debc1e 1345
022446ad 1346 r = sd_event_source_set_priority(client->timeout_t1,
e5002702 1347 client->event_priority);
b25ef18b
TG
1348 if (r < 0)
1349 return r;
1350
356779df 1351 r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer");
9021bb9f
TG
1352 if (r < 0)
1353 return r;
1354
022446ad 1355 log_dhcp_client(client, "T1 expires in %s",
ed19c567 1356 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
022446ad 1357
51debc1e
PF
1358 return 0;
1359}
1360
e5002702 1361static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
022446ad 1362 int len) {
574cc928 1363 DHCP_CLIENT_DONT_DESTROY(client);
e5002702 1364 int r = 0, notify_event = 0;
8c00042c 1365
b25ef18b
TG
1366 assert(client);
1367 assert(client->event);
e5002702 1368 assert(message);
b25ef18b 1369
8c00042c
PF
1370 switch (client->state) {
1371 case DHCP_STATE_SELECTING:
1372
e5002702
TG
1373 r = client_handle_offer(client, message, len);
1374 if (r >= 0) {
8c00042c 1375
8c00042c
PF
1376 client->timeout_resend =
1377 sd_event_source_unref(client->timeout_resend);
1378
1379 client->state = DHCP_STATE_REQUESTING;
e2dfc79f
PF
1380 client->attempt = 1;
1381
6a0f1f6d
LP
1382 r = sd_event_add_time(client->event,
1383 &client->timeout_resend,
fa94c34b 1384 clock_boottime_or_monotonic(),
6a0f1f6d
LP
1385 0, 0,
1386 client_timeout_resend, client);
3e3d8f78 1387 if (r < 0)
e2dfc79f 1388 goto error;
b25ef18b 1389
e5002702
TG
1390 r = sd_event_source_set_priority(client->timeout_resend,
1391 client->event_priority);
b25ef18b
TG
1392 if (r < 0)
1393 goto error;
9021bb9f 1394
356779df 1395 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
9021bb9f
TG
1396 if (r < 0)
1397 goto error;
9e64dd72
TG
1398 } else if (r == -ENOMSG)
1399 /* invalid message, let's ignore it */
1400 return 0;
8c00042c
PF
1401
1402 break;
1403
8b1243f7 1404 case DHCP_STATE_REBOOTING:
3e3d8f78 1405 case DHCP_STATE_REQUESTING:
aba26854 1406 case DHCP_STATE_RENEWING:
3dd71400 1407 case DHCP_STATE_REBINDING:
aba26854 1408
e5002702 1409 r = client_handle_ack(client, message, len);
2d2349cc 1410 if (r >= 0) {
3e3d8f78
PF
1411 client->timeout_resend =
1412 sd_event_source_unref(client->timeout_resend);
affaa94f
DW
1413 client->receive_message =
1414 sd_event_source_unref(client->receive_message);
1415 client->fd = asynchronous_close(client->fd);
3e3d8f78 1416
8b1243f7
PF
1417 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1418 DHCP_STATE_REBOOTING))
03748142
DH
1419 notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1420 else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
aba26854
PF
1421 notify_event = r;
1422
3e3d8f78
PF
1423 client->state = DHCP_STATE_BOUND;
1424 client->attempt = 1;
1425
1426 client->last_addr = client->lease->address;
1427
022446ad 1428 r = client_set_lease_timeouts(client);
0411760a
TG
1429 if (r < 0) {
1430 log_dhcp_client(client, "could not set lease timeouts");
51debc1e 1431 goto error;
0411760a 1432 }
51debc1e 1433
0af03ba5
TG
1434 r = dhcp_network_bind_udp_socket(client->lease->address,
1435 DHCP_PORT_CLIENT);
1436 if (r < 0) {
1437 log_dhcp_client(client, "could not bind UDP socket");
1438 goto error;
1439 }
1440
1441 client->fd = r;
1442
1443 client_initialize_io_events(client, client_receive_message_udp);
1444
e5b04c8d 1445 if (notify_event) {
574cc928
TG
1446 client_notify(client, notify_event);
1447 if (client->state == DHCP_STATE_STOPPED)
e5b04c8d
PF
1448 return 0;
1449 }
3e3d8f78 1450
2d2349cc
TG
1451 } else if (r == -EADDRNOTAVAIL) {
1452 /* got a NAK, let's restart the client */
1453 client->timeout_resend =
1454 sd_event_source_unref(client->timeout_resend);
1455
1456 r = client_initialize(client);
1457 if (r < 0)
1458 goto error;
1459
1460 r = client_start(client);
1461 if (r < 0)
1462 goto error;
1463
1464 log_dhcp_client(client, "REBOOTED");
1465
1466 return 0;
9e64dd72
TG
1467 } else if (r == -ENOMSG)
1468 /* invalid message, let's ignore it */
1469 return 0;
97b9372d 1470
3e3d8f78
PF
1471 break;
1472
615c1467
TG
1473 case DHCP_STATE_BOUND:
1474 r = client_handle_forcerenew(client, message, len);
1475 if (r >= 0) {
1476 r = client_timeout_t1(NULL, 0, client);
1477 if (r < 0)
1478 goto error;
1479 } else if (r == -ENOMSG)
1480 /* invalid message, let's ignore it */
1481 return 0;
1482
1483 break;
1484
8c00042c
PF
1485 case DHCP_STATE_INIT:
1486 case DHCP_STATE_INIT_REBOOT:
8c00042c
PF
1487
1488 break;
781ca7a1
PF
1489
1490 case DHCP_STATE_STOPPED:
1491 r = -EINVAL;
1492 goto error;
8c00042c
PF
1493 }
1494
1495error:
2d2349cc 1496 if (r < 0)
e5b04c8d 1497 client_stop(client, r);
e2dfc79f 1498
e5b04c8d 1499 return r;
8c00042c
PF
1500}
1501
8f61afd8 1502static int client_receive_message_udp(sd_event_source *s, int fd,
e5002702
TG
1503 uint32_t revents, void *userdata) {
1504 sd_dhcp_client *client = userdata;
5266a81e
TG
1505 _cleanup_free_ DHCPMessage *message = NULL;
1506 int buflen = 0, len, r;
76253e73 1507 const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
3dc05554 1508 const struct ether_addr *expected_chaddr = NULL;
76253e73 1509 uint8_t expected_hlen = 0;
e5002702
TG
1510
1511 assert(s);
1512 assert(client);
e5002702 1513
5266a81e 1514 r = ioctl(fd, FIONREAD, &buflen);
23289745
TG
1515 if (r < 0)
1516 return r;
1517
1518 if (buflen < 0)
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
TG
1527 if (len < 0) {
1528 log_dhcp_client(client, "could not receive message from UDP "
590b6b91 1529 "socket: %m");
0c79c68d 1530 return 0;
9fbc2523
TG
1531 } else if ((size_t)len < sizeof(DHCPMessage)) {
1532 log_dhcp_client(client, "too small to be a DHCP message: ignoring");
e5002702 1533 return 0;
9fbc2523
TG
1534 }
1535
1536 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1537 log_dhcp_client(client, "not a DHCP message: ignoring");
1538 return 0;
1539 }
1540
1541 if (message->op != BOOTREPLY) {
1542 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1543 return 0;
1544 }
1545
76253e73
DW
1546 if (message->htype != client->arp_type) {
1547 log_dhcp_client(client, "packet type does not match client type");
1548 return 0;
1549 }
1550
1551 if (client->arp_type == ARPHRD_ETHER) {
1552 expected_hlen = ETH_ALEN;
3dc05554 1553 expected_chaddr = (const struct ether_addr *) &client->mac_addr;
76253e73 1554 } else {
a8eaaee7 1555 /* Non-Ethernet links expect zero chaddr */
76253e73 1556 expected_hlen = 0;
3dc05554 1557 expected_chaddr = &zero_mac;
76253e73
DW
1558 }
1559
1560 if (message->hlen != expected_hlen) {
1561 log_dhcp_client(client, "unexpected packet hlen %d", message->hlen);
9fbc2523
TG
1562 return 0;
1563 }
1564
3dc05554 1565 if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
9fbc2523
TG
1566 log_dhcp_client(client, "received chaddr does not match "
1567 "expected: ignoring");
1568 return 0;
1569 }
e5002702 1570
615c1467
TG
1571 if (client->state != DHCP_STATE_BOUND &&
1572 be32toh(message->xid) != client->xid) {
1573 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1574 so ignore the xid in this case */
1575 log_dhcp_client(client, "received xid (%u) does not match "
1576 "expected (%u): ignoring",
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
TG
1604 if (r < 0)
1605 return r;
1606
1607 if (buflen < 0)
1608 /* this can't be right */
1609 return -EIO;
5266a81e
TG
1610
1611 packet = malloc0(buflen);
1612 if (!packet)
1613 return -ENOMEM;
1614
55dab2ed
TG
1615 iov.iov_base = packet;
1616 iov.iov_len = buflen;
1617
a38d9945 1618 len = recvmsg(fd, &msg, 0);
55dab2ed
TG
1619 if (len < 0) {
1620 log_dhcp_client(client, "could not receive message from raw "
590b6b91 1621 "socket: %m");
e5002702 1622 return 0;
0c79c68d
TG
1623 } else if ((size_t)len < sizeof(DHCPPacket))
1624 return 0;
55dab2ed 1625
2a1288ff 1626 CMSG_FOREACH(cmsg, &msg) {
48a4612e
TG
1627 if (cmsg->cmsg_level == SOL_PACKET &&
1628 cmsg->cmsg_type == PACKET_AUXDATA &&
1629 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1630 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
55dab2ed
TG
1631
1632 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1633 break;
1634 }
1635 }
e5002702 1636
55dab2ed 1637 r = dhcp_packet_verify_headers(packet, len, checksum);
ac4f16ab 1638 if (r < 0)
9fadd4ca 1639 return 0;
e5002702
TG
1640
1641 len -= DHCP_IP_UDP_SIZE;
1642
022446ad 1643 return client_handle_message(client, &packet->dhcp, len);
e5002702
TG
1644}
1645
5ee482df 1646int sd_dhcp_client_start(sd_dhcp_client *client) {
6a1cd41e 1647 int r;
d3d8ac2f 1648
46a66b79 1649 assert_return(client, -EINVAL);
46a66b79 1650
0f941add
PF
1651 r = client_initialize(client);
1652 if (r < 0)
6a1cd41e 1653 return r;
8c00042c 1654
0f941add
PF
1655 if (client->last_addr)
1656 client->state = DHCP_STATE_INIT_REBOOT;
d3d8ac2f 1657
998d8047
TG
1658 r = client_start(client);
1659 if (r >= 0)
1fa2f38f 1660 log_dhcp_client(client, "STARTED on ifindex %i", client->index);
998d8047
TG
1661
1662 return r;
46a66b79
PF
1663}
1664
5ee482df 1665int sd_dhcp_client_stop(sd_dhcp_client *client) {
574cc928
TG
1666 DHCP_CLIENT_DONT_DESTROY(client);
1667
e5b04c8d
PF
1668 assert_return(client, -EINVAL);
1669
03748142 1670 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
574cc928 1671 client->state = DHCP_STATE_STOPPED;
e5b04c8d
PF
1672
1673 return 0;
bbdf06d9
PF
1674}
1675
e5002702
TG
1676int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1677 int priority) {
b25ef18b
TG
1678 int r;
1679
1680 assert_return(client, -EINVAL);
1681 assert_return(!client->event, -EBUSY);
1682
1683 if (event)
1684 client->event = sd_event_ref(event);
1685 else {
1686 r = sd_event_default(&client->event);
1687 if (r < 0)
1688 return 0;
1689 }
1690
1691 client->event_priority = priority;
1692
1693 return 0;
1694}
1695
1696int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1697 assert_return(client, -EINVAL);
1698
1699 client->event = sd_event_unref(client->event);
1700
1701 return 0;
1702}
1703
1704sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1705 if (!client)
1706 return NULL;
1707
1708 return client->event;
1709}
1710
e5b04c8d 1711sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
3733eec3
LP
1712
1713 if (!client)
1714 return NULL;
1715
1716 assert(client->n_ref >= 1);
1717 client->n_ref++;
e5b04c8d
PF
1718
1719 return client;
1720}
1721
1722sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
d2fe46b5 1723
3733eec3
LP
1724 if (!client)
1725 return NULL;
e5b04c8d 1726
3733eec3
LP
1727 assert(client->n_ref >= 1);
1728 client->n_ref--;
e5b04c8d 1729
3733eec3
LP
1730 if (client->n_ref > 0)
1731 return NULL;
e5b04c8d 1732
3733eec3 1733 log_dhcp_client(client, "FREE");
6e00a806 1734
3733eec3
LP
1735 client_initialize(client);
1736
1737 client->receive_message = sd_event_source_unref(client->receive_message);
1738
1739 sd_dhcp_client_detach_event(client);
1740
1741 sd_dhcp_lease_unref(client->lease);
1742
1743 free(client->req_opts);
1744 free(client->hostname);
1745 free(client->vendor_class_identifier);
1746 free(client);
d2fe46b5 1747
574cc928 1748 return NULL;
d2fe46b5
PF
1749}
1750
b25ef18b 1751int sd_dhcp_client_new(sd_dhcp_client **ret) {
574cc928 1752 _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
011feef8 1753
b25ef18b 1754 assert_return(ret, -EINVAL);
d3d8ac2f 1755
011feef8
PF
1756 client = new0(sd_dhcp_client, 1);
1757 if (!client)
b25ef18b 1758 return -ENOMEM;
011feef8 1759
3733eec3 1760 client->n_ref = 1;
011feef8
PF
1761 client->state = DHCP_STATE_INIT;
1762 client->index = -1;
8c00042c 1763 client->fd = -1;
e2dfc79f 1764 client->attempt = 1;
324f8187 1765 client->mtu = DHCP_DEFAULT_MIN_SIZE;
011feef8
PF
1766
1767 client->req_opts_size = ELEMENTSOF(default_req_opts);
1768
1769 client->req_opts = memdup(default_req_opts, client->req_opts_size);
b25ef18b
TG
1770 if (!client->req_opts)
1771 return -ENOMEM;
1772
1773 *ret = client;
1774 client = NULL;
011feef8 1775
b25ef18b 1776 return 0;
011feef8 1777}