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