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