chiark / gitweb /
489220326e90843872e246b7956ced1e6a6b24bd
[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         return client_initialize_events(client, client_receive_message_raw);
748 }
749
750 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
751                              void *userdata) {
752         sd_dhcp_client *client = userdata;
753         int r;
754
755         client->state = DHCP_STATE_RENEWING;
756         client->attempt = 1;
757
758         r = dhcp_network_bind_udp_socket(client->index,
759                                          client->lease->address,
760                                          DHCP_PORT_CLIENT);
761         if (r < 0) {
762                 client_stop(client, r);
763                 return 0;
764         }
765
766         client->fd = r;
767
768         return client_initialize_events(client, client_receive_message_udp);
769 }
770
771 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
772                                size_t len) {
773         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
774         int r;
775
776         r = dhcp_lease_new(&lease);
777         if (r < 0)
778                 return r;
779
780         r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
781         if (r != DHCP_OFFER) {
782                 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
783                 return -ENOMSG;
784         }
785
786         lease->next_server = offer->siaddr;
787
788         lease->address = offer->yiaddr;
789
790         if (lease->address == INADDR_ANY ||
791             lease->server_address == INADDR_ANY ||
792             lease->lifetime == 0) {
793                 log_dhcp_client(client, "receieved lease lacks address, server "
794                                 "address or lease lifetime, ignoring");
795                 return -ENOMSG;
796         }
797
798         if (lease->subnet_mask == INADDR_ANY) {
799                 r = dhcp_lease_set_default_subnet_mask(lease);
800                 if (r < 0) {
801                         log_dhcp_client(client, "receieved lease lacks subnet "
802                                         "mask, and a fallback one can not be "
803                                         "generated, ignoring");
804                         return -ENOMSG;
805                 }
806         }
807
808         sd_dhcp_lease_unref(client->lease);
809         client->lease = lease;
810         lease = NULL;
811
812         log_dhcp_client(client, "OFFER");
813
814         return 0;
815 }
816
817 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
818                              size_t len) {
819         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
820         int r;
821
822         r = dhcp_lease_new(&lease);
823         if (r < 0)
824                 return r;
825
826         r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
827         if (r == DHCP_NAK) {
828                 log_dhcp_client(client, "NAK");
829                 return DHCP_EVENT_NO_LEASE;
830         }
831
832         if (r != DHCP_ACK) {
833                 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
834                 return -ENOMSG;
835         }
836
837         lease->next_server = ack->siaddr;
838
839         lease->address = ack->yiaddr;
840
841         if (lease->address == INADDR_ANY ||
842             lease->server_address == INADDR_ANY ||
843             lease->lifetime == 0) {
844                 log_dhcp_client(client, "receieved lease lacks address, server "
845                                 "address or lease lifetime, ignoring");
846                 return -ENOMSG;
847         }
848
849         if (lease->subnet_mask == INADDR_ANY) {
850                 r = dhcp_lease_set_default_subnet_mask(lease);
851                 if (r < 0) {
852                         log_dhcp_client(client, "receieved lease lacks subnet "
853                                         "mask, and a fallback one can not be "
854                                         "generated, ignoring");
855                         return -ENOMSG;
856                 }
857         }
858
859         r = DHCP_EVENT_IP_ACQUIRE;
860         if (client->lease) {
861                 if (client->lease->address != lease->address ||
862                     client->lease->subnet_mask != lease->subnet_mask ||
863                     client->lease->router != lease->router) {
864                         r = DHCP_EVENT_IP_CHANGE;
865                 }
866
867                 client->lease = sd_dhcp_lease_unref(client->lease);
868         }
869
870         client->lease = lease;
871         lease = NULL;
872
873         log_dhcp_client(client, "ACK");
874
875         return r;
876 }
877
878 static uint64_t client_compute_timeout(sd_dhcp_client *client,
879                                        uint32_t lifetime, double factor) {
880         assert(client);
881         assert(client->request_sent);
882         assert(lifetime);
883
884         return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
885                 + (random_u32() & 0x1fffff);
886 }
887
888 static int client_set_lease_timeouts(sd_dhcp_client *client) {
889         usec_t time_now;
890         uint64_t lifetime_timeout;
891         uint64_t t2_timeout;
892         uint64_t t1_timeout;
893         char time_string[FORMAT_TIMESPAN_MAX];
894         int r;
895
896         assert(client);
897         assert(client->event);
898         assert(client->lease);
899         assert(client->lease->lifetime);
900
901         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
902         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
903         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
904
905         /* don't set timers for infinite leases */
906         if (client->lease->lifetime == 0xffffffff)
907                 return 0;
908
909         r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
910         if (r < 0)
911                 return r;
912         assert(client->request_sent <= time_now);
913
914         /* convert the various timeouts from relative (secs) to absolute (usecs) */
915         lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
916         if (client->lease->t1 && client->lease->t2) {
917                 /* both T1 and T2 are given */
918                 if (client->lease->t1 < client->lease->t2 &&
919                     client->lease->t2 < client->lease->lifetime) {
920                         /* they are both valid */
921                         t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
922                         t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
923                 } else {
924                         /* discard both */
925                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
926                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
927                         t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
928                         client->lease->t1 = client->lease->lifetime / 2;
929                 }
930         } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
931                 /* only T2 is given, and it is valid */
932                 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
933                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
934                 client->lease->t1 = client->lease->lifetime / 2;
935                 if (t2_timeout <= t1_timeout) {
936                         /* the computed T1 would be invalid, so discard T2 */
937                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
938                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
939                 }
940         } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
941                 /* only T1 is given, and it is valid */
942                 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
943                 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
944                 client->lease->t2 = (client->lease->lifetime * 7) / 8;
945                 if (t2_timeout <= t1_timeout) {
946                         /* the computed T2 would be invalid, so discard T1 */
947                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
948                         client->lease->t2 = client->lease->lifetime / 2;
949                 }
950         } else {
951                 /* fall back to the default timeouts */
952                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
953                 client->lease->t1 = client->lease->lifetime / 2;
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
958         /* arm lifetime timeout */
959         r = sd_event_add_time(client->event, &client->timeout_expire,
960                               CLOCK_MONOTONIC,
961                               lifetime_timeout, 10 * USEC_PER_MSEC,
962                               client_timeout_expire, client);
963         if (r < 0)
964                 return r;
965
966         r = sd_event_source_set_priority(client->timeout_expire,
967                                          client->event_priority);
968         if (r < 0)
969                 return r;
970
971         log_dhcp_client(client, "lease expires in %s",
972                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
973                         lifetime_timeout - time_now, 0));
974
975         /* don't arm earlier timeouts if this has already expired */
976         if (lifetime_timeout <= time_now)
977                 return 0;
978
979         /* arm T2 timeout */
980         r = sd_event_add_time(client->event,
981                               &client->timeout_t2,
982                               CLOCK_MONOTONIC,
983                               t2_timeout,
984                               10 * USEC_PER_MSEC,
985                               client_timeout_t2, client);
986         if (r < 0)
987                 return r;
988
989         r = sd_event_source_set_priority(client->timeout_t2,
990                                          client->event_priority);
991         if (r < 0)
992                 return r;
993
994         log_dhcp_client(client, "T2 expires in %s",
995                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
996                         t2_timeout - time_now, 0));
997
998         /* don't arm earlier timeout if this has already expired */
999         if (t2_timeout <= time_now)
1000                 return 0;
1001
1002         /* arm T1 timeout */
1003         r = sd_event_add_time(client->event,
1004                               &client->timeout_t1,
1005                               CLOCK_MONOTONIC,
1006                               t1_timeout, 10 * USEC_PER_MSEC,
1007                               client_timeout_t1, client);
1008         if (r < 0)
1009                 return r;
1010
1011         r = sd_event_source_set_priority(client->timeout_t1,
1012                                          client->event_priority);
1013         if (r < 0)
1014                 return r;
1015
1016         log_dhcp_client(client, "T1 expires in %s",
1017                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1018                         t1_timeout - time_now, 0));
1019
1020         return 0;
1021 }
1022
1023 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1024                                  int len) {
1025         int r = 0, notify_event = 0;
1026
1027         assert(client);
1028         assert(client->event);
1029         assert(message);
1030
1031         if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1032                 log_dhcp_client(client, "not a DHCP message: ignoring");
1033                 return 0;
1034         }
1035
1036         if (message->op != BOOTREPLY) {
1037                 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1038                 return 0;
1039         }
1040
1041         if (be32toh(message->xid) != client->xid) {
1042                 log_dhcp_client(client, "received xid (%u) does not match "
1043                                 "expected (%u): ignoring",
1044                                 be32toh(message->xid), client->xid);
1045                 return 0;
1046         }
1047
1048         if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1049                 log_dhcp_client(client, "not an ethernet packet");
1050                 return 0;
1051         }
1052
1053         if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1054                    ETH_ALEN)) {
1055                 log_dhcp_client(client, "received chaddr does not match "
1056                                 "expected: ignoring");
1057                 return 0;
1058         }
1059
1060         switch (client->state) {
1061         case DHCP_STATE_SELECTING:
1062
1063                 r = client_handle_offer(client, message, len);
1064                 if (r >= 0) {
1065
1066                         client->timeout_resend =
1067                                 sd_event_source_unref(client->timeout_resend);
1068
1069                         client->state = DHCP_STATE_REQUESTING;
1070                         client->attempt = 1;
1071
1072                         r = sd_event_add_time(client->event,
1073                                               &client->timeout_resend,
1074                                               CLOCK_MONOTONIC,
1075                                               0, 0,
1076                                               client_timeout_resend, client);
1077                         if (r < 0)
1078                                 goto error;
1079
1080                         r = sd_event_source_set_priority(client->timeout_resend,
1081                                                          client->event_priority);
1082                         if (r < 0)
1083                                 goto error;
1084                 } else if (r == -ENOMSG)
1085                         /* invalid message, let's ignore it */
1086                         return 0;
1087
1088                 break;
1089
1090         case DHCP_STATE_REBOOTING:
1091         case DHCP_STATE_REQUESTING:
1092         case DHCP_STATE_RENEWING:
1093         case DHCP_STATE_REBINDING:
1094
1095                 r = client_handle_ack(client, message, len);
1096                 if (r == DHCP_EVENT_NO_LEASE) {
1097
1098                         client->timeout_resend =
1099                                 sd_event_source_unref(client->timeout_resend);
1100
1101                         if (client->state == DHCP_STATE_REBOOTING) {
1102                                 r = client_initialize(client);
1103                                 if (r < 0)
1104                                         goto error;
1105
1106                                 r = client_start(client);
1107                                 if (r < 0)
1108                                         goto error;
1109
1110                                 log_dhcp_client(client, "REBOOTED");
1111                         }
1112
1113                         goto error;
1114                 } else if (r >= 0) {
1115                         client->timeout_resend =
1116                                 sd_event_source_unref(client->timeout_resend);
1117
1118                         if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1119                                    DHCP_STATE_REBOOTING))
1120                                 notify_event = DHCP_EVENT_IP_ACQUIRE;
1121                         else if (r != DHCP_EVENT_IP_ACQUIRE)
1122                                 notify_event = r;
1123
1124                         client->state = DHCP_STATE_BOUND;
1125                         client->attempt = 1;
1126
1127                         client->last_addr = client->lease->address;
1128
1129                         r = client_set_lease_timeouts(client);
1130                         if (r < 0)
1131                                 goto error;
1132
1133                         if (notify_event) {
1134                                 client = client_notify(client, notify_event);
1135                                 if (!client ||
1136                                     client->state == DHCP_STATE_STOPPED)
1137                                         return 0;
1138                         }
1139
1140                         client->receive_message =
1141                                 sd_event_source_unref(client->receive_message);
1142                         client->fd = safe_close(client->fd);
1143                 } else if (r == -ENOMSG)
1144                         /* invalid message, let's ignore it */
1145                         return 0;
1146
1147                 break;
1148
1149         case DHCP_STATE_INIT:
1150         case DHCP_STATE_INIT_REBOOT:
1151         case DHCP_STATE_BOUND:
1152
1153                 break;
1154
1155         case DHCP_STATE_STOPPED:
1156                 r = -EINVAL;
1157                 goto error;
1158         }
1159
1160 error:
1161         if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1162                 client_stop(client, r);
1163
1164         return r;
1165 }
1166
1167 static int client_receive_message_udp(sd_event_source *s, int fd,
1168                                       uint32_t revents, void *userdata) {
1169         sd_dhcp_client *client = userdata;
1170         _cleanup_free_ DHCPMessage *message = NULL;
1171         int buflen = 0, len, r;
1172
1173         assert(s);
1174         assert(client);
1175
1176         r = ioctl(fd, FIONREAD, &buflen);
1177         if (r < 0 || buflen <= 0)
1178                 buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE;
1179
1180         message = malloc0(buflen);
1181         if (!message)
1182                 return -ENOMEM;
1183
1184         len = read(fd, message, buflen);
1185         if (len < 0) {
1186                 log_dhcp_client(client, "could not receive message from UDP "
1187                                 "socket: %s", strerror(errno));
1188                 return 0;
1189         } else if ((size_t)len < sizeof(DHCPMessage))
1190                 return 0;
1191
1192         return client_handle_message(client, message, len);
1193 }
1194
1195 static int client_receive_message_raw(sd_event_source *s, int fd,
1196                                       uint32_t revents, void *userdata) {
1197         sd_dhcp_client *client = userdata;
1198         _cleanup_free_ DHCPPacket *packet = NULL;
1199         uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1200         struct iovec iov = {};
1201         struct msghdr msg = {
1202                 .msg_iov = &iov,
1203                 .msg_iovlen = 1,
1204                 .msg_control = cmsgbuf,
1205                 .msg_controllen = sizeof(cmsgbuf),
1206         };
1207         struct cmsghdr *cmsg;
1208         bool checksum = true;
1209         int buflen = 0, len, r;
1210
1211         assert(s);
1212         assert(client);
1213
1214         r = ioctl(fd, FIONREAD, &buflen);
1215         if (r < 0 || buflen <= 0)
1216                 buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE;
1217
1218         packet = malloc0(buflen);
1219         if (!packet)
1220                 return -ENOMEM;
1221
1222         iov.iov_base = packet;
1223         iov.iov_len = buflen;
1224
1225         len = recvmsg(fd, &msg, 0);
1226         if (len < 0) {
1227                 log_dhcp_client(client, "could not receive message from raw "
1228                                 "socket: %s", strerror(errno));
1229                 return 0;
1230         } else if ((size_t)len < sizeof(DHCPPacket))
1231                 return 0;
1232
1233         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1234                 if (cmsg->cmsg_level == SOL_PACKET &&
1235                     cmsg->cmsg_type == PACKET_AUXDATA &&
1236                     cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1237                         struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1238
1239                         checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1240                         break;
1241                 }
1242         }
1243
1244         r = dhcp_packet_verify_headers(packet, len, checksum);
1245         if (r < 0)
1246                 return 0;
1247
1248         len -= DHCP_IP_UDP_SIZE;
1249
1250         return client_handle_message(client, &packet->dhcp, len);
1251 }
1252
1253 int sd_dhcp_client_start(sd_dhcp_client *client) {
1254         int r;
1255
1256         assert_return(client, -EINVAL);
1257
1258         r = client_initialize(client);
1259         if (r < 0)
1260                 return r;
1261
1262         if (client->last_addr)
1263                 client->state = DHCP_STATE_INIT_REBOOT;
1264
1265         r = client_start(client);
1266         if (r >= 0)
1267                 log_dhcp_client(client, "STARTED");
1268
1269         return r;
1270 }
1271
1272 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1273         assert_return(client, -EINVAL);
1274
1275         if (client_stop(client, DHCP_EVENT_STOP))
1276                 client->state = DHCP_STATE_STOPPED;
1277
1278         return 0;
1279 }
1280
1281 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1282                                 int priority) {
1283         int r;
1284
1285         assert_return(client, -EINVAL);
1286         assert_return(!client->event, -EBUSY);
1287
1288         if (event)
1289                 client->event = sd_event_ref(event);
1290         else {
1291                 r = sd_event_default(&client->event);
1292                 if (r < 0)
1293                         return 0;
1294         }
1295
1296         client->event_priority = priority;
1297
1298         return 0;
1299 }
1300
1301 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1302         assert_return(client, -EINVAL);
1303
1304         client->event = sd_event_unref(client->event);
1305
1306         return 0;
1307 }
1308
1309 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1310         if (!client)
1311                 return NULL;
1312
1313         return client->event;
1314 }
1315
1316 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1317         if (client)
1318                 assert_se(REFCNT_INC(client->n_ref) >= 2);
1319
1320         return client;
1321 }
1322
1323 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1324         if (client && REFCNT_DEC(client->n_ref) <= 0) {
1325                 log_dhcp_client(client, "UNREF");
1326
1327                 client_initialize(client);
1328
1329                 client->receive_message =
1330                         sd_event_source_unref(client->receive_message);
1331
1332                 sd_dhcp_client_detach_event(client);
1333
1334                 sd_dhcp_lease_unref(client->lease);
1335
1336                 free(client->req_opts);
1337                 free(client);
1338
1339                 return NULL;
1340         }
1341
1342         return client;
1343 }
1344
1345 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
1346 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1347
1348 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1349         _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1350
1351         assert_return(ret, -EINVAL);
1352
1353         client = new0(sd_dhcp_client, 1);
1354         if (!client)
1355                 return -ENOMEM;
1356
1357         client->n_ref = REFCNT_INIT;
1358         client->state = DHCP_STATE_INIT;
1359         client->index = -1;
1360         client->fd = -1;
1361         client->attempt = 1;
1362
1363         client->req_opts_size = ELEMENTSOF(default_req_opts);
1364
1365         client->req_opts = memdup(default_req_opts, client->req_opts_size);
1366         if (!client->req_opts)
1367                 return -ENOMEM;
1368
1369         *ret = client;
1370         client = NULL;
1371
1372         return 0;
1373 }