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