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