chiark / gitweb /
sd-dhcp-client: log positive error number
[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
34 #include "dhcp-protocol.h"
35 #include "dhcp-internal.h"
36 #include "dhcp-lease-internal.h"
37 #include "sd-dhcp-client.h"
38
39 struct sd_dhcp_client {
40         RefCount n_ref;
41
42         DHCPState state;
43         sd_event *event;
44         int event_priority;
45         sd_event_source *timeout_resend;
46         int index;
47         int fd;
48         union sockaddr_union link;
49         sd_event_source *receive_message;
50         uint8_t *req_opts;
51         size_t req_opts_allocated;
52         size_t req_opts_size;
53         be32_t last_addr;
54         struct {
55                 uint8_t type;
56                 struct ether_addr mac_addr;
57         } _packed_ client_id;
58         uint32_t xid;
59         usec_t start_time;
60         uint16_t secs;
61         unsigned int attempt;
62         usec_t request_sent;
63         sd_event_source *timeout_t1;
64         sd_event_source *timeout_t2;
65         sd_event_source *timeout_expire;
66         sd_dhcp_client_cb_t cb;
67         void *userdata;
68         sd_dhcp_lease *lease;
69 };
70
71 static const uint8_t default_req_opts[] = {
72         DHCP_OPTION_SUBNET_MASK,
73         DHCP_OPTION_ROUTER,
74         DHCP_OPTION_HOST_NAME,
75         DHCP_OPTION_DOMAIN_NAME,
76         DHCP_OPTION_DOMAIN_NAME_SERVER,
77         DHCP_OPTION_NTP_SERVER,
78 };
79
80 static int client_receive_message_raw(sd_event_source *s, int fd,
81                                       uint32_t revents, void *userdata);
82 static int client_receive_message_udp(sd_event_source *s, int fd,
83                                       uint32_t revents, void *userdata);
84 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error);
85
86 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
87                                 void *userdata) {
88         assert_return(client, -EINVAL);
89
90         client->cb = cb;
91         client->userdata = userdata;
92
93         return 0;
94 }
95
96 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
97         size_t i;
98
99         assert_return(client, -EINVAL);
100         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
101                               DHCP_STATE_STOPPED), -EBUSY);
102
103         switch(option) {
104         case DHCP_OPTION_PAD:
105         case DHCP_OPTION_OVERLOAD:
106         case DHCP_OPTION_MESSAGE_TYPE:
107         case DHCP_OPTION_PARAMETER_REQUEST_LIST:
108         case DHCP_OPTION_END:
109                 return -EINVAL;
110
111         default:
112                 break;
113         }
114
115         for (i = 0; i < client->req_opts_size; i++)
116                 if (client->req_opts[i] == option)
117                         return -EEXIST;
118
119         if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
120                             client->req_opts_size + 1))
121                 return -ENOMEM;
122
123         client->req_opts[client->req_opts_size++] = option;
124
125         return 0;
126 }
127
128 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
129                                        const struct in_addr *last_addr) {
130         assert_return(client, -EINVAL);
131         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
132                               DHCP_STATE_STOPPED), -EBUSY);
133
134         if (last_addr)
135                 client->last_addr = last_addr->s_addr;
136         else
137                 client->last_addr = INADDR_ANY;
138
139         return 0;
140 }
141
142 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
143         assert_return(client, -EINVAL);
144         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
145                               DHCP_STATE_STOPPED), -EBUSY);
146         assert_return(interface_index > 0, -EINVAL);
147
148         client->index = interface_index;
149
150         return 0;
151 }
152
153 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
154                            const struct ether_addr *addr) {
155         bool need_restart = false;
156
157         assert_return(client, -EINVAL);
158         assert_return(addr, -EINVAL);
159
160         if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
161                 return 0;
162
163         if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
164                 log_dhcp_client(client, "Changing MAC address on running DHCP "
165                                 "client, restarting");
166                 need_restart = true;
167                 client = client_stop(client, DHCP_EVENT_STOP);
168         }
169
170         if (!client)
171                 return 0;
172
173         memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
174         client->client_id.type = 0x01;
175
176         if (need_restart && client->state != DHCP_STATE_STOPPED)
177                 sd_dhcp_client_start(client);
178
179         return 0;
180 }
181
182 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
183         assert_return(client, -EINVAL);
184         assert_return(ret, -EINVAL);
185
186         if (client->state != DHCP_STATE_BOUND &&
187             client->state != DHCP_STATE_RENEWING &&
188             client->state != DHCP_STATE_REBINDING)
189                 return -EADDRNOTAVAIL;
190
191         *ret = sd_dhcp_lease_ref(client->lease);
192
193         return 0;
194 }
195
196 static sd_dhcp_client *client_notify(sd_dhcp_client *client, int event) {
197         if (client->cb) {
198                 client = sd_dhcp_client_ref(client);
199                 client->cb(client, event, client->userdata);
200                 client = sd_dhcp_client_unref(client);
201         }
202
203         return client;
204 }
205
206 static int client_initialize(sd_dhcp_client *client) {
207         assert_return(client, -EINVAL);
208
209         client->receive_message =
210                 sd_event_source_unref(client->receive_message);
211
212         client->fd = safe_close(client->fd);
213
214         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
215
216         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
217         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
218         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
219
220         client->attempt = 1;
221
222         client->state = DHCP_STATE_INIT;
223         client->xid = 0;
224
225         if (client->lease)
226                 client->lease = sd_dhcp_lease_unref(client->lease);
227
228         return 0;
229 }
230
231 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error) {
232         assert_return(client, NULL);
233
234         if (error < 0)
235                 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
236         else {
237                 switch(error) {
238                 case DHCP_EVENT_STOP:
239                         log_dhcp_client(client, "STOPPED: Requested by user");
240                         break;
241                 case DHCP_EVENT_NO_LEASE:
242                         log_dhcp_client(client, "STOPPED: No lease");
243                         break;
244                 default:
245                         log_dhcp_client(client, "STOPPED: Unknown reason");
246                         break;
247                 }
248         }
249
250         client = client_notify(client, error);
251
252         if (client)
253                 client_initialize(client);
254
255         return client;
256 }
257
258 static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
259                                uint8_t type, uint8_t **opt, size_t *optlen) {
260         be16_t max_size;
261         int r;
262
263         assert(client);
264         assert(client->secs);
265         assert(message);
266         assert(opt);
267         assert(optlen);
268         assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
269
270         r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt,
271                               optlen);
272         if (r < 0)
273                 return r;
274
275         /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
276            refuse to issue an DHCP lease if 'secs' is set to zero */
277         message->secs = htobe16(client->secs);
278
279         /* RFC2132 section 4.1.1:
280            The client MUST include its hardware address in the ’chaddr’ field, if
281            necessary for delivery of DHCP reply messages.
282          */
283         memcpy(&message->chaddr, &client->client_id.mac_addr, ETH_ALEN);
284
285         /* Some DHCP servers will refuse to issue an DHCP lease if the Client
286            Identifier option is not set */
287         r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
288                                sizeof(client->client_id), &client->client_id);
289         if (r < 0)
290                 return r;
291
292
293         /* RFC2131 section 3.5:
294            in its initial DHCPDISCOVER or DHCPREQUEST message, a
295            client may provide the server with a list of specific
296            parameters the client is interested in. If the client
297            includes a list of parameters in a DHCPDISCOVER message,
298            it MUST include that list in any subsequent DHCPREQUEST
299            messages.
300          */
301         r = dhcp_option_append(opt, optlen,
302                                DHCP_OPTION_PARAMETER_REQUEST_LIST,
303                                client->req_opts_size,
304                                client->req_opts);
305         if (r < 0)
306                 return r;
307
308         /* RFC2131 section 3.5:
309            The client SHOULD include the ’maximum DHCP message size’ option to
310            let the server know how large the server may make its DHCP messages.
311
312            Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
313            than the defined default size unless the Maximum Messge Size option
314            is explicitely set
315          */
316         max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
317                            DHCP_MIN_OPTIONS_SIZE);
318         r = dhcp_option_append(opt, optlen,
319                                DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
320                                2, &max_size);
321         if (r < 0)
322                 return r;
323
324         return 0;
325 }
326
327 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
328                                 size_t len) {
329         dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
330                                       INADDR_BROADCAST, DHCP_PORT_SERVER, len);
331
332         return dhcp_network_send_raw_socket(client->fd, &client->link,
333                                             packet, len);
334 }
335
336 static int client_send_discover(sd_dhcp_client *client) {
337         _cleanup_free_ DHCPPacket *discover = NULL;
338         size_t optlen, len;
339         uint8_t *opt;
340         usec_t time_now;
341         int r;
342
343         assert(client);
344         assert(client->state == DHCP_STATE_INIT ||
345                client->state == DHCP_STATE_SELECTING);
346
347         /* See RFC2131 section 4.4.1 */
348
349         r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
350         if (r < 0)
351                 return r;
352         assert(time_now >= client->start_time);
353
354         /* seconds between sending first and last DISCOVER
355          * must always be strictly positive to deal with broken servers */
356         client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
357
358         optlen = DHCP_MIN_OPTIONS_SIZE;
359         len = sizeof(DHCPPacket) + optlen;
360
361         discover = malloc0(len);
362         if (!discover)
363                 return -ENOMEM;
364
365         r = client_message_init(client, &discover->dhcp, DHCP_DISCOVER,
366                                 &opt, &optlen);
367         if (r < 0)
368                 return r;
369
370         /* the client may suggest values for the network address
371            and lease time in the DHCPDISCOVER message. The client may include
372            the ’requested IP address’ option to suggest that a particular IP
373            address be assigned, and may include the ’IP address lease time’
374            option to suggest the lease time it would like.
375          */
376         if (client->last_addr != INADDR_ANY) {
377                 r = dhcp_option_append(&opt, &optlen,
378                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
379                                          4, &client->last_addr);
380                 if (r < 0)
381                         return r;
382         }
383
384         r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
385         if (r < 0)
386                 return r;
387
388         /* We currently ignore:
389            The client SHOULD wait a random time between one and ten seconds to
390            desynchronize the use of DHCP at startup.
391          */
392         r = dhcp_client_send_raw(client, discover, len - optlen);
393         if (r < 0)
394                 return r;
395
396         log_dhcp_client(client, "DISCOVER");
397
398         return 0;
399 }
400
401 static int client_send_request(sd_dhcp_client *client) {
402         _cleanup_free_ DHCPPacket *request;
403         size_t optlen, len;
404         uint8_t *opt;
405         int r;
406
407         optlen = DHCP_MIN_OPTIONS_SIZE;
408         len = sizeof(DHCPPacket) + optlen;
409
410         request = malloc0(len);
411         if (!request)
412                 return -ENOMEM;
413
414         r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt,
415                                 &optlen);
416         if (r < 0)
417                 return r;
418
419         switch (client->state) {
420         /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
421            SELECTING should be REQUESTING)
422          */
423
424         case DHCP_STATE_REQUESTING:
425                 /* Client inserts the address of the selected server in ’server
426                    identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
427                    filled in with the yiaddr value from the chosen DHCPOFFER.
428                  */
429
430                 r = dhcp_option_append(&opt, &optlen,
431                                        DHCP_OPTION_SERVER_IDENTIFIER,
432                                        4, &client->lease->server_address);
433                 if (r < 0)
434                         return r;
435
436                 r = dhcp_option_append(&opt, &optlen,
437                                        DHCP_OPTION_REQUESTED_IP_ADDRESS,
438                                        4, &client->lease->address);
439                 if (r < 0)
440                         return r;
441
442                 break;
443
444         case DHCP_STATE_INIT_REBOOT:
445                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
446                    option MUST be filled in with client’s notion of its previously
447                    assigned address. ’ciaddr’ MUST be zero.
448                  */
449                 r = dhcp_option_append(&opt, &optlen,
450                                        DHCP_OPTION_REQUESTED_IP_ADDRESS,
451                                        4, &client->last_addr);
452                 if (r < 0)
453                         return r;
454                 break;
455
456         case DHCP_STATE_RENEWING:
457                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
458                    option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
459                    client’s IP address.
460                 */
461
462                 /* fall through */
463         case DHCP_STATE_REBINDING:
464                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
465                    option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
466                    client’s IP address.
467
468                    This message MUST be broadcast to the 0xffffffff IP broadcast address.
469                  */
470                 request->dhcp.ciaddr = client->lease->address;
471
472                 break;
473
474         case DHCP_STATE_INIT:
475         case DHCP_STATE_SELECTING:
476         case DHCP_STATE_REBOOTING:
477         case DHCP_STATE_BOUND:
478         case DHCP_STATE_STOPPED:
479                 return -EINVAL;
480         }
481
482         r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
483         if (r < 0)
484                 return r;
485
486         if (client->state == DHCP_STATE_RENEWING) {
487                 r = dhcp_network_send_udp_socket(client->fd,
488                                                  client->lease->server_address,
489                                                  DHCP_PORT_SERVER,
490                                                  &request->dhcp,
491                                                  len - optlen - DHCP_IP_UDP_SIZE);
492         } else {
493                 r = dhcp_client_send_raw(client, request, len - optlen);
494         }
495         if (r < 0)
496                 return r;
497
498         switch (client->state) {
499         case DHCP_STATE_REQUESTING:
500                 log_dhcp_client(client, "REQUEST (requesting)");
501                 break;
502         case DHCP_STATE_INIT_REBOOT:
503                 log_dhcp_client(client, "REQUEST (init-reboot)");
504                 break;
505         case DHCP_STATE_RENEWING:
506                 log_dhcp_client(client, "REQUEST (renewing)");
507                 break;
508         case DHCP_STATE_REBINDING:
509                 log_dhcp_client(client, "REQUEST (rebinding)");
510                 break;
511         default:
512                 log_dhcp_client(client, "REQUEST (invalid)");
513                 break;
514         }
515
516         return 0;
517 }
518
519 static int client_start(sd_dhcp_client *client);
520
521 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
522                                  void *userdata) {
523         sd_dhcp_client *client = userdata;
524         usec_t next_timeout = 0;
525         uint64_t time_now;
526         uint32_t time_left;
527         int r;
528
529         assert(s);
530         assert(client);
531         assert(client->event);
532
533         r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
534         if (r < 0)
535                 goto error;
536
537         switch (client->state) {
538         case DHCP_STATE_RENEWING:
539
540                 time_left = (client->lease->t2 - client->lease->t1) / 2;
541                 if (time_left < 60)
542                         time_left = 60;
543
544                 next_timeout = time_now + time_left * USEC_PER_SEC;
545
546                 break;
547
548         case DHCP_STATE_REBINDING:
549
550                 time_left = (client->lease->lifetime - client->lease->t2) / 2;
551                 if (time_left < 60)
552                         time_left = 60;
553
554                 next_timeout = time_now + time_left * USEC_PER_SEC;
555                 break;
556
557         case DHCP_STATE_REBOOTING:
558                 /* start over as we did not receive a timely ack or nak */
559                 r = client_initialize(client);
560                 if (r < 0)
561                         goto error;
562
563                 r = client_start(client);
564                 if (r < 0)
565                         goto error;
566                 else {
567                         log_dhcp_client(client, "REBOOTED");
568                         return 0;
569                 }
570
571         case DHCP_STATE_INIT:
572         case DHCP_STATE_INIT_REBOOT:
573         case DHCP_STATE_SELECTING:
574         case DHCP_STATE_REQUESTING:
575         case DHCP_STATE_BOUND:
576
577                 if (client->attempt < 64)
578                         client->attempt *= 2;
579
580                 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
581
582                 break;
583
584         case DHCP_STATE_STOPPED:
585                 r = -EINVAL;
586                 goto error;
587         }
588
589         next_timeout += (random_u32() & 0x1fffff);
590
591         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
592
593         r = sd_event_add_time(client->event,
594                               &client->timeout_resend,
595                               CLOCK_MONOTONIC,
596                               next_timeout, 10 * USEC_PER_MSEC,
597                               client_timeout_resend, client);
598         if (r < 0)
599                 goto error;
600
601         r = sd_event_source_set_priority(client->timeout_resend,
602                                          client->event_priority);
603         if (r < 0)
604                 goto error;
605
606         switch (client->state) {
607         case DHCP_STATE_INIT:
608                 r = client_send_discover(client);
609                 if (r >= 0) {
610                         client->state = DHCP_STATE_SELECTING;
611                         client->attempt = 1;
612                 } else {
613                         if (client->attempt >= 64)
614                                 goto error;
615                 }
616
617                 break;
618
619         case DHCP_STATE_SELECTING:
620                 r = client_send_discover(client);
621                 if (r < 0 && client->attempt >= 64)
622                         goto error;
623
624                 break;
625
626         case DHCP_STATE_INIT_REBOOT:
627         case DHCP_STATE_REQUESTING:
628         case DHCP_STATE_RENEWING:
629         case DHCP_STATE_REBINDING:
630                 r = client_send_request(client);
631                 if (r < 0 && client->attempt >= 64)
632                          goto error;
633
634                 if (client->state == DHCP_STATE_INIT_REBOOT)
635                         client->state = DHCP_STATE_REBOOTING;
636
637                 client->request_sent = time_now;
638
639                 break;
640
641         case DHCP_STATE_REBOOTING:
642         case DHCP_STATE_BOUND:
643
644                 break;
645
646         case DHCP_STATE_STOPPED:
647                 r = -EINVAL;
648                 goto error;
649         }
650
651         return 0;
652
653 error:
654         client_stop(client, r);
655
656         /* Errors were dealt with when stopping the client, don't spill
657            errors into the event loop handler */
658         return 0;
659 }
660
661 static int client_initialize_events(sd_dhcp_client *client,
662                                     sd_event_io_handler_t io_callback) {
663         int r;
664
665         assert(client);
666         assert(client->event);
667
668         r = sd_event_add_io(client->event, &client->receive_message,
669                             client->fd, EPOLLIN, io_callback,
670                             client);
671         if (r < 0)
672                 goto error;
673
674         r = sd_event_source_set_priority(client->receive_message,
675                                          client->event_priority);
676         if (r < 0)
677                 goto error;
678
679         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
680
681         r = sd_event_add_time(client->event,
682                               &client->timeout_resend,
683                               CLOCK_MONOTONIC,
684                               0, 0,
685                               client_timeout_resend, client);
686         if (r < 0)
687                 goto error;
688
689         r = sd_event_source_set_priority(client->timeout_resend,
690                                          client->event_priority);
691
692 error:
693         if (r < 0)
694                 client_stop(client, r);
695
696         return 0;
697
698 }
699
700 static int client_start(sd_dhcp_client *client) {
701         int r;
702
703         assert_return(client, -EINVAL);
704         assert_return(client->event, -EINVAL);
705         assert_return(client->index > 0, -EINVAL);
706         assert_return(client->fd < 0, -EBUSY);
707         assert_return(client->xid == 0, -EINVAL);
708         assert_return(client->state == DHCP_STATE_INIT ||
709                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
710
711         client->xid = random_u32();
712
713         r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
714         if (r < 0) {
715                 client_stop(client, r);
716                 return r;
717         }
718         client->fd = r;
719
720         if (client->state == DHCP_STATE_INIT) {
721                 client->start_time = now(CLOCK_MONOTONIC);
722                 client->secs = 0;
723         }
724
725         return client_initialize_events(client, client_receive_message_raw);
726 }
727
728 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
729                                  void *userdata) {
730         sd_dhcp_client *client = userdata;
731
732         log_dhcp_client(client, "EXPIRED");
733
734         client = client_notify(client, DHCP_EVENT_EXPIRED);
735
736         /* lease was lost, start over if not freed or stopped in callback */
737         if (client && client->state != DHCP_STATE_STOPPED) {
738                 client_initialize(client);
739                 client_start(client);
740         }
741
742         return 0;
743 }
744
745 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
746         sd_dhcp_client *client = userdata;
747         int r;
748
749         client->receive_message = sd_event_source_unref(client->receive_message);
750         client->fd = safe_close(client->fd);
751
752         client->state = DHCP_STATE_REBINDING;
753         client->attempt = 1;
754
755         r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
756         if (r < 0) {
757                 client_stop(client, r);
758                 return 0;
759         }
760         client->fd = r;
761
762         return client_initialize_events(client, client_receive_message_raw);
763 }
764
765 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
766                              void *userdata) {
767         sd_dhcp_client *client = userdata;
768         int r;
769
770         client->state = DHCP_STATE_RENEWING;
771         client->attempt = 1;
772
773         r = dhcp_network_bind_udp_socket(client->index,
774                                          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 = safe_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 }