chiark / gitweb /
test-dhcp-client: unref lease objects to make valgrind happy
[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 }