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