]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-client.c
Fix a few typos in log messages
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-client.c
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>
24 #include <net/ethernet.h>
25 #include <net/if_arp.h>
26 #include <netinet/ether.h>
27 #include <sys/param.h>
28 #include <sys/ioctl.h>
29
30 #include "util.h"
31 #include "list.h"
32 #include "refcnt.h"
33 #include "async.h"
34
35 #include "dhcp-protocol.h"
36 #include "dhcp-internal.h"
37 #include "dhcp-lease-internal.h"
38 #include "sd-dhcp-client.h"
39
40 struct sd_dhcp_client {
41 RefCount n_ref;
42
43 DHCPState state;
44 sd_event *event;
45 int event_priority;
46 sd_event_source *timeout_resend;
47 int index;
48 int fd;
49 union sockaddr_union link;
50 sd_event_source *receive_message;
51 bool request_broadcast;
52 uint8_t *req_opts;
53 size_t req_opts_allocated;
54 size_t req_opts_size;
55 be32_t last_addr;
56 struct {
57 uint8_t type;
58 struct ether_addr mac_addr;
59 } _packed_ client_id;
60 char *hostname;
61 char *vendor_class_identifier;
62 uint32_t mtu;
63 uint32_t xid;
64 usec_t start_time;
65 uint16_t secs;
66 unsigned int attempt;
67 usec_t request_sent;
68 sd_event_source *timeout_t1;
69 sd_event_source *timeout_t2;
70 sd_event_source *timeout_expire;
71 sd_dhcp_client_cb_t cb;
72 void *userdata;
73 sd_dhcp_lease *lease;
74 };
75
76 static 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
85 static int client_receive_message_raw(sd_event_source *s, int fd,
86 uint32_t revents, void *userdata);
87 static int client_receive_message_udp(sd_event_source *s, int fd,
88 uint32_t revents, void *userdata);
89 static void client_stop(sd_dhcp_client *client, int error);
90
91 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
92 void *userdata) {
93 assert_return(client, -EINVAL);
94
95 client->cb = cb;
96 client->userdata = userdata;
97
98 return 0;
99 }
100
101 int 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
109 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
110 size_t i;
111
112 assert_return(client, -EINVAL);
113 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
114 DHCP_STATE_STOPPED), -EBUSY);
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
132 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
133 client->req_opts_size + 1))
134 return -ENOMEM;
135
136 client->req_opts[client->req_opts_size++] = option;
137
138 return 0;
139 }
140
141 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
142 const struct in_addr *last_addr) {
143 assert_return(client, -EINVAL);
144 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
145 DHCP_STATE_STOPPED), -EBUSY);
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
155 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
156 assert_return(client, -EINVAL);
157 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
158 DHCP_STATE_STOPPED), -EBUSY);
159 assert_return(interface_index > 0, -EINVAL);
160
161 client->index = interface_index;
162
163 return 0;
164 }
165
166 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
167 const struct ether_addr *addr) {
168 DHCP_CLIENT_DONT_DESTROY(client);
169 bool need_restart = false;
170
171 assert_return(client, -EINVAL);
172 assert_return(addr, -EINVAL);
173
174 if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
175 return 0;
176
177 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
178 log_dhcp_client(client, "Changing MAC address on running DHCP "
179 "client, restarting");
180 need_restart = true;
181 client_stop(client, DHCP_EVENT_STOP);
182 }
183
184 memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
185 client->client_id.type = 0x01;
186
187 if (need_restart && client->state != DHCP_STATE_STOPPED)
188 sd_dhcp_client_start(client);
189
190 return 0;
191 }
192
193 int 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
214 int 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
231 int 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
240 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
241 assert_return(client, -EINVAL);
242 assert_return(ret, -EINVAL);
243
244 if (client->state != DHCP_STATE_BOUND &&
245 client->state != DHCP_STATE_RENEWING &&
246 client->state != DHCP_STATE_REBINDING)
247 return -EADDRNOTAVAIL;
248
249 *ret = sd_dhcp_lease_ref(client->lease);
250
251 return 0;
252 }
253
254 static void client_notify(sd_dhcp_client *client, int event) {
255 if (client->cb)
256 client->cb(client, event, client->userdata);
257 }
258
259 static int client_initialize(sd_dhcp_client *client) {
260 assert_return(client, -EINVAL);
261
262 client->receive_message =
263 sd_event_source_unref(client->receive_message);
264
265 client->fd = asynchronous_close(client->fd);
266
267 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
268
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
273 client->attempt = 1;
274
275 client->state = DHCP_STATE_INIT;
276 client->xid = 0;
277
278 if (client->lease)
279 client->lease = sd_dhcp_lease_unref(client->lease);
280
281 return 0;
282 }
283
284 static void client_stop(sd_dhcp_client *client, int error) {
285 assert(client);
286
287 if (error < 0)
288 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
289 else if (error == DHCP_EVENT_STOP)
290 log_dhcp_client(client, "STOPPED");
291 else
292 log_dhcp_client(client, "STOPPED: Unknown event");
293
294 client_notify(client, error);
295
296 client_initialize(client);
297 }
298
299 static 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;
303 be16_t max_size;
304 int r;
305
306 assert(client);
307 assert(client->secs);
308 assert(ret);
309 assert(_optlen);
310 assert(_optoffset);
311 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
312
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);
322 if (r < 0)
323 return r;
324
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 */
327 packet->dhcp.secs = htobe16(client->secs);
328
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
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);
342
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 */
347 memcpy(&packet->dhcp.chaddr, &client->client_id.mac_addr, ETH_ALEN);
348
349 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
350 Identifier option is not set */
351 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
352 DHCP_OPTION_CLIENT_IDENTIFIER,
353 sizeof(client->client_id), &client->client_id);
354 if (r < 0)
355 return r;
356
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 */
366 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
367 DHCP_OPTION_PARAMETER_REQUEST_LIST,
368 client->req_opts_size, client->req_opts);
369 if (r < 0)
370 return r;
371
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
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.)
393 */
394 max_size = htobe16(size);
395 r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
396 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
397 2, &max_size);
398 if (r < 0)
399 return r;
400
401 *_optlen = optlen;
402 *_optoffset = optoffset;
403 *ret = packet;
404 packet = NULL;
405
406 return 0;
407 }
408
409 static 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
418 static int client_send_discover(sd_dhcp_client *client) {
419 _cleanup_free_ DHCPPacket *discover = NULL;
420 size_t optoffset, optlen;
421 usec_t time_now;
422 int r;
423
424 assert(client);
425 assert(client->state == DHCP_STATE_INIT ||
426 client->state == DHCP_STATE_SELECTING);
427
428 /* See RFC2131 section 4.4.1 */
429
430 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
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;
438
439 r = client_message_init(client, &discover, DHCP_DISCOVER,
440 &optlen, &optoffset);
441 if (r < 0)
442 return r;
443
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 */
450 if (client->last_addr != INADDR_ANY) {
451 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
452 DHCP_OPTION_REQUESTED_IP_ADDRESS,
453 4, &client->last_addr);
454 if (r < 0)
455 return r;
456 }
457
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
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
478 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
479 DHCP_OPTION_END, 0, NULL);
480 if (r < 0)
481 return r;
482
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 */
487 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
488 if (r < 0)
489 return r;
490
491 log_dhcp_client(client, "DISCOVER");
492
493 return 0;
494 }
495
496 static int client_send_request(sd_dhcp_client *client) {
497 _cleanup_free_ DHCPPacket *request = NULL;
498 size_t optoffset, optlen;
499 int r;
500
501 r = client_message_init(client, &request, DHCP_REQUEST,
502 &optlen, &optoffset);
503 if (r < 0)
504 return r;
505
506 switch (client->state) {
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 */
516
517 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
518 DHCP_OPTION_SERVER_IDENTIFIER,
519 4, &client->lease->server_address);
520 if (r < 0)
521 return r;
522
523 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
524 DHCP_OPTION_REQUESTED_IP_ADDRESS,
525 4, &client->lease->address);
526 if (r < 0)
527 return r;
528
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 */
536 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
537 DHCP_OPTION_REQUESTED_IP_ADDRESS,
538 4, &client->last_addr);
539 if (r < 0)
540 return r;
541 break;
542
543 case DHCP_STATE_RENEWING:
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 */
550 case DHCP_STATE_REBINDING:
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;
558
559 break;
560
561 case DHCP_STATE_INIT:
562 case DHCP_STATE_SELECTING:
563 case DHCP_STATE_REBOOTING:
564 case DHCP_STATE_BOUND:
565 case DHCP_STATE_STOPPED:
566 return -EINVAL;
567 }
568
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
577 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
578 DHCP_OPTION_END, 0, NULL);
579 if (r < 0)
580 return r;
581
582 if (client->state == DHCP_STATE_RENEWING) {
583 r = dhcp_network_send_udp_socket(client->fd,
584 client->lease->server_address,
585 DHCP_PORT_SERVER,
586 &request->dhcp,
587 sizeof(DHCPMessage) + optoffset);
588 } else {
589 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
590 }
591 if (r < 0)
592 return r;
593
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 }
611
612 return 0;
613 }
614
615 static int client_start(sd_dhcp_client *client);
616
617 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
618 void *userdata) {
619 sd_dhcp_client *client = userdata;
620 DHCP_CLIENT_DONT_DESTROY(client);
621 usec_t next_timeout = 0;
622 uint64_t time_now;
623 uint32_t time_left;
624 int r;
625
626 assert(s);
627 assert(client);
628 assert(client->event);
629
630 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
631 if (r < 0)
632 goto error;
633
634 switch (client->state) {
635 case DHCP_STATE_RENEWING:
636
637 time_left = (client->lease->t2 - client->lease->t1) / 2;
638 if (time_left < 60)
639 time_left = 60;
640
641 next_timeout = time_now + time_left * USEC_PER_SEC;
642
643 break;
644
645 case DHCP_STATE_REBINDING:
646
647 time_left = (client->lease->lifetime - client->lease->t2) / 2;
648 if (time_left < 60)
649 time_left = 60;
650
651 next_timeout = time_now + time_left * USEC_PER_SEC;
652 break;
653
654 case DHCP_STATE_REBOOTING:
655 /* start over as we did not receive a timely ack or nak */
656 r = client_initialize(client);
657 if (r < 0)
658 goto error;
659
660 r = client_start(client);
661 if (r < 0)
662 goto error;
663 else {
664 log_dhcp_client(client, "REBOOTED");
665 return 0;
666 }
667
668 case DHCP_STATE_INIT:
669 case DHCP_STATE_INIT_REBOOT:
670 case DHCP_STATE_SELECTING:
671 case DHCP_STATE_REQUESTING:
672 case DHCP_STATE_BOUND:
673
674 if (client->attempt < 64)
675 client->attempt *= 2;
676
677 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
678
679 break;
680
681 case DHCP_STATE_STOPPED:
682 r = -EINVAL;
683 goto error;
684 }
685
686 next_timeout += (random_u32() & 0x1fffff);
687
688 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
689
690 r = sd_event_add_time(client->event,
691 &client->timeout_resend,
692 clock_boottime_or_monotonic(),
693 next_timeout, 10 * USEC_PER_MSEC,
694 client_timeout_resend, client);
695 if (r < 0)
696 goto error;
697
698 r = sd_event_source_set_priority(client->timeout_resend,
699 client->event_priority);
700 if (r < 0)
701 goto error;
702
703 r = sd_event_source_set_name(client->timeout_resend,
704 "dhcp4-resend-timer");
705 if (r < 0)
706 goto error;
707
708 switch (client->state) {
709 case DHCP_STATE_INIT:
710 r = client_send_discover(client);
711 if (r >= 0) {
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:
722 r = client_send_discover(client);
723 if (r < 0 && client->attempt >= 64)
724 goto error;
725
726 break;
727
728 case DHCP_STATE_INIT_REBOOT:
729 case DHCP_STATE_REQUESTING:
730 case DHCP_STATE_RENEWING:
731 case DHCP_STATE_REBINDING:
732 r = client_send_request(client);
733 if (r < 0 && client->attempt >= 64)
734 goto error;
735
736 if (client->state == DHCP_STATE_INIT_REBOOT)
737 client->state = DHCP_STATE_REBOOTING;
738
739 client->request_sent = time_now;
740
741 break;
742
743 case DHCP_STATE_REBOOTING:
744 case DHCP_STATE_BOUND:
745
746 break;
747
748 case DHCP_STATE_STOPPED:
749 r = -EINVAL;
750 goto error;
751 }
752
753 return 0;
754
755 error:
756 client_stop(client, r);
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
763 static int client_initialize_io_events(sd_dhcp_client *client,
764 sd_event_io_handler_t io_callback) {
765 int r;
766
767 assert(client);
768 assert(client->event);
769
770 r = sd_event_add_io(client->event, &client->receive_message,
771 client->fd, EPOLLIN, io_callback,
772 client);
773 if (r < 0)
774 goto error;
775
776 r = sd_event_source_set_priority(client->receive_message,
777 client->event_priority);
778 if (r < 0)
779 goto error;
780
781 r = sd_event_source_set_name(client->receive_message,
782 "dhcp4-receive-message");
783 if (r < 0)
784 goto error;
785
786 error:
787 if (r < 0)
788 client_stop(client, r);
789
790 return 0;
791 }
792
793 static int client_initialize_time_events(sd_dhcp_client *client) {
794 int r;
795
796 assert(client);
797 assert(client->event);
798
799 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
800
801 r = sd_event_add_time(client->event,
802 &client->timeout_resend,
803 clock_boottime_or_monotonic(),
804 0, 0,
805 client_timeout_resend, client);
806 if (r < 0)
807 goto error;
808
809 r = sd_event_source_set_priority(client->timeout_resend,
810 client->event_priority);
811
812 r = sd_event_source_set_name(client->timeout_resend,
813 "dhcp4-resend-timer");
814 if (r < 0)
815 goto error;
816
817 error:
818 if (r < 0)
819 client_stop(client, r);
820
821 return 0;
822
823 }
824
825 static 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
833 static 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
846 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
847 if (r < 0) {
848 client_stop(client, r);
849 return r;
850 }
851 client->fd = r;
852
853 if (client->state == DHCP_STATE_INIT) {
854 client->start_time = now(clock_boottime_or_monotonic());
855 client->secs = 0;
856 }
857
858 return client_initialize_events(client, client_receive_message_raw);
859 }
860
861 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
862 void *userdata) {
863 sd_dhcp_client *client = userdata;
864 DHCP_CLIENT_DONT_DESTROY(client);
865
866 log_dhcp_client(client, "EXPIRED");
867
868 client_notify(client, DHCP_EVENT_EXPIRED);
869
870 /* lease was lost, start over if not freed or stopped in callback */
871 if (client->state != DHCP_STATE_STOPPED) {
872 client_initialize(client);
873 client_start(client);
874 }
875
876 return 0;
877 }
878
879 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
880 sd_dhcp_client *client = userdata;
881 DHCP_CLIENT_DONT_DESTROY(client);
882 int r;
883
884 client->receive_message = sd_event_source_unref(client->receive_message);
885 client->fd = asynchronous_close(client->fd);
886
887 client->state = DHCP_STATE_REBINDING;
888 client->attempt = 1;
889
890 r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
891 if (r < 0) {
892 client_stop(client, r);
893 return 0;
894 }
895 client->fd = r;
896
897 return client_initialize_events(client, client_receive_message_raw);
898 }
899
900 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
901 void *userdata) {
902 sd_dhcp_client *client = userdata;
903 DHCP_CLIENT_DONT_DESTROY(client);
904
905 client->state = DHCP_STATE_RENEWING;
906 client->attempt = 1;
907
908 return client_initialize_time_events(client);
909 }
910
911 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
912 size_t len) {
913 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
914 int r;
915
916 r = dhcp_lease_new(&lease);
917 if (r < 0)
918 return r;
919
920 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
921 if (r != DHCP_OFFER) {
922 log_dhcp_client(client, "received message was not an OFFER, ignoring");
923 return -ENOMSG;
924 }
925
926 lease->next_server = offer->siaddr;
927
928 lease->address = offer->yiaddr;
929
930 if (lease->address == INADDR_ANY ||
931 lease->server_address == INADDR_ANY ||
932 lease->lifetime == 0) {
933 log_dhcp_client(client, "received lease lacks address, server "
934 "address or lease lifetime, ignoring");
935 return -ENOMSG;
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, "received lease lacks subnet "
942 "mask, and a fallback one can not be "
943 "generated, ignoring");
944 return -ENOMSG;
945 }
946 }
947
948 sd_dhcp_lease_unref(client->lease);
949 client->lease = lease;
950 lease = NULL;
951
952 log_dhcp_client(client, "OFFER");
953
954 return 0;
955 }
956
957 static 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
970 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
971 size_t len) {
972 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
973 int r;
974
975 r = dhcp_lease_new(&lease);
976 if (r < 0)
977 return r;
978
979 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
980 if (r == DHCP_NAK) {
981 log_dhcp_client(client, "NAK");
982 return -EADDRNOTAVAIL;
983 }
984
985 if (r != DHCP_ACK) {
986 log_dhcp_client(client, "received message was not an ACK, ignoring");
987 return -ENOMSG;
988 }
989
990 lease->next_server = ack->siaddr;
991
992 lease->address = ack->yiaddr;
993
994 if (lease->address == INADDR_ANY ||
995 lease->server_address == INADDR_ANY ||
996 lease->lifetime == 0) {
997 log_dhcp_client(client, "received lease lacks address, server "
998 "address or lease lifetime, ignoring");
999 return -ENOMSG;
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, "received lease lacks subnet "
1006 "mask, and a fallback one can not be "
1007 "generated, ignoring");
1008 return -ENOMSG;
1009 }
1010 }
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;
1018 } else
1019 r = DHCP_EVENT_RENEW;
1020
1021 client->lease = sd_dhcp_lease_unref(client->lease);
1022 }
1023
1024 client->lease = lease;
1025 lease = NULL;
1026
1027 log_dhcp_client(client, "ACK");
1028
1029 return r;
1030 }
1031
1032 static 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) +
1039 + (random_u32() & 0x1fffff);
1040 }
1041
1042 static 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];
1048 int r;
1049
1050 assert(client);
1051 assert(client->event);
1052 assert(client->lease);
1053 assert(client->lease->lifetime);
1054
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
1059 /* don't set timers for infinite leases */
1060 if (client->lease->lifetime == 0xffffffff)
1061 return 0;
1062
1063 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
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 }
1111
1112 /* arm lifetime timeout */
1113 r = sd_event_add_time(client->event, &client->timeout_expire,
1114 clock_boottime_or_monotonic(),
1115 lifetime_timeout, 10 * USEC_PER_MSEC,
1116 client_timeout_expire, client);
1117 if (r < 0)
1118 return r;
1119
1120 r = sd_event_source_set_priority(client->timeout_expire,
1121 client->event_priority);
1122 if (r < 0)
1123 return r;
1124
1125 r = sd_event_source_set_name(client->timeout_expire,
1126 "dhcp4-lifetime");
1127 if (r < 0)
1128 return r;
1129
1130 log_dhcp_client(client, "lease expires in %s",
1131 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1132 lifetime_timeout - time_now, 0));
1133
1134 /* don't arm earlier timeouts if this has already expired */
1135 if (lifetime_timeout <= time_now)
1136 return 0;
1137
1138 /* arm T2 timeout */
1139 r = sd_event_add_time(client->event,
1140 &client->timeout_t2,
1141 clock_boottime_or_monotonic(),
1142 t2_timeout,
1143 10 * USEC_PER_MSEC,
1144 client_timeout_t2, client);
1145 if (r < 0)
1146 return r;
1147
1148 r = sd_event_source_set_priority(client->timeout_t2,
1149 client->event_priority);
1150 if (r < 0)
1151 return r;
1152
1153 r = sd_event_source_set_name(client->timeout_t2,
1154 "dhcp4-t2-timeout");
1155 if (r < 0)
1156 return r;
1157
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;
1165
1166 /* arm T1 timeout */
1167 r = sd_event_add_time(client->event,
1168 &client->timeout_t1,
1169 clock_boottime_or_monotonic(),
1170 t1_timeout, 10 * USEC_PER_MSEC,
1171 client_timeout_t1, client);
1172 if (r < 0)
1173 return r;
1174
1175 r = sd_event_source_set_priority(client->timeout_t1,
1176 client->event_priority);
1177 if (r < 0)
1178 return r;
1179
1180 r = sd_event_source_set_name(client->timeout_t1,
1181 "dhcp4-t1-timer");
1182 if (r < 0)
1183 return r;
1184
1185 log_dhcp_client(client, "T1 expires in %s",
1186 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1187 t1_timeout - time_now, 0));
1188
1189 return 0;
1190 }
1191
1192 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1193 int len) {
1194 DHCP_CLIENT_DONT_DESTROY(client);
1195 int r = 0, notify_event = 0;
1196
1197 assert(client);
1198 assert(client->event);
1199 assert(message);
1200
1201 switch (client->state) {
1202 case DHCP_STATE_SELECTING:
1203
1204 r = client_handle_offer(client, message, len);
1205 if (r >= 0) {
1206
1207 client->timeout_resend =
1208 sd_event_source_unref(client->timeout_resend);
1209
1210 client->state = DHCP_STATE_REQUESTING;
1211 client->attempt = 1;
1212
1213 r = sd_event_add_time(client->event,
1214 &client->timeout_resend,
1215 clock_boottime_or_monotonic(),
1216 0, 0,
1217 client_timeout_resend, client);
1218 if (r < 0)
1219 goto error;
1220
1221 r = sd_event_source_set_priority(client->timeout_resend,
1222 client->event_priority);
1223 if (r < 0)
1224 goto error;
1225
1226 r = sd_event_source_set_name(client->timeout_resend,
1227 "dhcp4-resend-timer");
1228 if (r < 0)
1229 goto error;
1230 } else if (r == -ENOMSG)
1231 /* invalid message, let's ignore it */
1232 return 0;
1233
1234 break;
1235
1236 case DHCP_STATE_REBOOTING:
1237 case DHCP_STATE_REQUESTING:
1238 case DHCP_STATE_RENEWING:
1239 case DHCP_STATE_REBINDING:
1240
1241 r = client_handle_ack(client, message, len);
1242 if (r >= 0) {
1243 client->timeout_resend =
1244 sd_event_source_unref(client->timeout_resend);
1245
1246 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1247 DHCP_STATE_REBOOTING))
1248 notify_event = DHCP_EVENT_IP_ACQUIRE;
1249 else if (r != DHCP_EVENT_IP_ACQUIRE)
1250 notify_event = r;
1251
1252 client->state = DHCP_STATE_BOUND;
1253 client->attempt = 1;
1254
1255 client->last_addr = client->lease->address;
1256
1257 r = client_set_lease_timeouts(client);
1258 if (r < 0)
1259 goto error;
1260
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
1272 if (notify_event) {
1273 client_notify(client, notify_event);
1274 if (client->state == DHCP_STATE_STOPPED)
1275 return 0;
1276 }
1277
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;
1294 } else if (r == -ENOMSG)
1295 /* invalid message, let's ignore it */
1296 return 0;
1297
1298 break;
1299
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
1312 case DHCP_STATE_INIT:
1313 case DHCP_STATE_INIT_REBOOT:
1314
1315 break;
1316
1317 case DHCP_STATE_STOPPED:
1318 r = -EINVAL;
1319 goto error;
1320 }
1321
1322 error:
1323 if (r < 0)
1324 client_stop(client, r);
1325
1326 return r;
1327 }
1328
1329 static int client_receive_message_udp(sd_event_source *s, int fd,
1330 uint32_t revents, void *userdata) {
1331 sd_dhcp_client *client = userdata;
1332 _cleanup_free_ DHCPMessage *message = NULL;
1333 int buflen = 0, len, r;
1334
1335 assert(s);
1336 assert(client);
1337
1338 r = ioctl(fd, FIONREAD, &buflen);
1339 if (r < 0)
1340 return r;
1341
1342 if (buflen < 0)
1343 /* this can't be right */
1344 return -EIO;
1345
1346 message = malloc0(buflen);
1347 if (!message)
1348 return -ENOMEM;
1349
1350 len = read(fd, message, buflen);
1351 if (len < 0) {
1352 log_dhcp_client(client, "could not receive message from UDP "
1353 "socket: %m");
1354 return 0;
1355 } else if ((size_t)len < sizeof(DHCPMessage)) {
1356 log_dhcp_client(client, "too small to be a DHCP message: ignoring");
1357 return 0;
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
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 }
1381
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
1392 return client_handle_message(client, message, len);
1393 }
1394
1395 static int client_receive_message_raw(sd_event_source *s, int fd,
1396 uint32_t revents, void *userdata) {
1397 sd_dhcp_client *client = userdata;
1398 _cleanup_free_ DHCPPacket *packet = NULL;
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;
1410
1411 assert(s);
1412 assert(client);
1413
1414 r = ioctl(fd, FIONREAD, &buflen);
1415 if (r < 0)
1416 return r;
1417
1418 if (buflen < 0)
1419 /* this can't be right */
1420 return -EIO;
1421
1422 packet = malloc0(buflen);
1423 if (!packet)
1424 return -ENOMEM;
1425
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 "
1432 "socket: %m");
1433 return 0;
1434 } else if ((size_t)len < sizeof(DHCPPacket))
1435 return 0;
1436
1437 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
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);
1442
1443 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1444 break;
1445 }
1446 }
1447
1448 r = dhcp_packet_verify_headers(packet, len, checksum);
1449 if (r < 0)
1450 return 0;
1451
1452 len -= DHCP_IP_UDP_SIZE;
1453
1454 return client_handle_message(client, &packet->dhcp, len);
1455 }
1456
1457 int sd_dhcp_client_start(sd_dhcp_client *client) {
1458 char buffer[ETHER_ADDR_TO_STRING_MAX];
1459 int r;
1460
1461 assert_return(client, -EINVAL);
1462
1463 r = client_initialize(client);
1464 if (r < 0)
1465 return r;
1466
1467 if (client->last_addr)
1468 client->state = DHCP_STATE_INIT_REBOOT;
1469
1470 r = client_start(client);
1471 if (r >= 0)
1472 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1473 client->index,
1474 ether_addr_to_string(&client->client_id.mac_addr, buffer));
1475
1476 return r;
1477 }
1478
1479 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1480 DHCP_CLIENT_DONT_DESTROY(client);
1481
1482 assert_return(client, -EINVAL);
1483
1484 client_stop(client, DHCP_EVENT_STOP);
1485 client->state = DHCP_STATE_STOPPED;
1486
1487 return 0;
1488 }
1489
1490 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1491 int priority) {
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
1510 int 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
1518 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1519 if (!client)
1520 return NULL;
1521
1522 return client->event;
1523 }
1524
1525 sd_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
1532 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1533 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1534 log_dhcp_client(client, "FREE");
1535
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
1543 sd_dhcp_lease_unref(client->lease);
1544
1545 free(client->req_opts);
1546 free(client->hostname);
1547 free(client->vendor_class_identifier);
1548 free(client);
1549 }
1550
1551 return NULL;
1552 }
1553
1554 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1555 _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1556
1557 assert_return(ret, -EINVAL);
1558
1559 client = new0(sd_dhcp_client, 1);
1560 if (!client)
1561 return -ENOMEM;
1562
1563 client->n_ref = REFCNT_INIT;
1564 client->state = DHCP_STATE_INIT;
1565 client->index = -1;
1566 client->fd = -1;
1567 client->attempt = 1;
1568 client->mtu = DHCP_DEFAULT_MIN_SIZE;
1569
1570 client->req_opts_size = ELEMENTSOF(default_req_opts);
1571
1572 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1573 if (!client->req_opts)
1574 return -ENOMEM;
1575
1576 *ret = client;
1577 client = NULL;
1578
1579 return 0;
1580 }