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