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