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