chiark / gitweb /
dhcp-network: don't pass ifindex to bind_udp_socket
[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->lease->address,
774                                          DHCP_PORT_CLIENT);
775         if (r < 0) {
776                 client_stop(client, r);
777                 return 0;
778         }
779
780         client->fd = r;
781
782         return client_initialize_events(client, client_receive_message_udp);
783 }
784
785 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
786                                size_t len) {
787         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
788         int r;
789
790         r = dhcp_lease_new(&lease);
791         if (r < 0)
792                 return r;
793
794         r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
795         if (r != DHCP_OFFER) {
796                 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
797                 return -ENOMSG;
798         }
799
800         lease->next_server = offer->siaddr;
801
802         lease->address = offer->yiaddr;
803
804         if (lease->address == INADDR_ANY ||
805             lease->server_address == INADDR_ANY ||
806             lease->lifetime == 0) {
807                 log_dhcp_client(client, "receieved lease lacks address, server "
808                                 "address or lease lifetime, ignoring");
809                 return -ENOMSG;
810         }
811
812         if (lease->subnet_mask == INADDR_ANY) {
813                 r = dhcp_lease_set_default_subnet_mask(lease);
814                 if (r < 0) {
815                         log_dhcp_client(client, "receieved lease lacks subnet "
816                                         "mask, and a fallback one can not be "
817                                         "generated, ignoring");
818                         return -ENOMSG;
819                 }
820         }
821
822         sd_dhcp_lease_unref(client->lease);
823         client->lease = lease;
824         lease = NULL;
825
826         log_dhcp_client(client, "OFFER");
827
828         return 0;
829 }
830
831 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
832                              size_t len) {
833         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
834         int r;
835
836         r = dhcp_lease_new(&lease);
837         if (r < 0)
838                 return r;
839
840         r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
841         if (r == DHCP_NAK) {
842                 log_dhcp_client(client, "NAK");
843                 return DHCP_EVENT_NO_LEASE;
844         }
845
846         if (r != DHCP_ACK) {
847                 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
848                 return -ENOMSG;
849         }
850
851         lease->next_server = ack->siaddr;
852
853         lease->address = ack->yiaddr;
854
855         if (lease->address == INADDR_ANY ||
856             lease->server_address == INADDR_ANY ||
857             lease->lifetime == 0) {
858                 log_dhcp_client(client, "receieved lease lacks address, server "
859                                 "address or lease lifetime, ignoring");
860                 return -ENOMSG;
861         }
862
863         if (lease->subnet_mask == INADDR_ANY) {
864                 r = dhcp_lease_set_default_subnet_mask(lease);
865                 if (r < 0) {
866                         log_dhcp_client(client, "receieved lease lacks subnet "
867                                         "mask, and a fallback one can not be "
868                                         "generated, ignoring");
869                         return -ENOMSG;
870                 }
871         }
872
873         r = DHCP_EVENT_IP_ACQUIRE;
874         if (client->lease) {
875                 if (client->lease->address != lease->address ||
876                     client->lease->subnet_mask != lease->subnet_mask ||
877                     client->lease->router != lease->router) {
878                         r = DHCP_EVENT_IP_CHANGE;
879                 }
880
881                 client->lease = sd_dhcp_lease_unref(client->lease);
882         }
883
884         client->lease = lease;
885         lease = NULL;
886
887         log_dhcp_client(client, "ACK");
888
889         return r;
890 }
891
892 static uint64_t client_compute_timeout(sd_dhcp_client *client,
893                                        uint32_t lifetime, double factor) {
894         assert(client);
895         assert(client->request_sent);
896         assert(lifetime);
897
898         return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
899                 + (random_u32() & 0x1fffff);
900 }
901
902 static int client_set_lease_timeouts(sd_dhcp_client *client) {
903         usec_t time_now;
904         uint64_t lifetime_timeout;
905         uint64_t t2_timeout;
906         uint64_t t1_timeout;
907         char time_string[FORMAT_TIMESPAN_MAX];
908         int r;
909
910         assert(client);
911         assert(client->event);
912         assert(client->lease);
913         assert(client->lease->lifetime);
914
915         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
916         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
917         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
918
919         /* don't set timers for infinite leases */
920         if (client->lease->lifetime == 0xffffffff)
921                 return 0;
922
923         r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
924         if (r < 0)
925                 return r;
926         assert(client->request_sent <= time_now);
927
928         /* convert the various timeouts from relative (secs) to absolute (usecs) */
929         lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
930         if (client->lease->t1 && client->lease->t2) {
931                 /* both T1 and T2 are given */
932                 if (client->lease->t1 < client->lease->t2 &&
933                     client->lease->t2 < client->lease->lifetime) {
934                         /* they are both valid */
935                         t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
936                         t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
937                 } else {
938                         /* discard both */
939                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
940                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
941                         t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
942                         client->lease->t1 = client->lease->lifetime / 2;
943                 }
944         } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
945                 /* only T2 is given, and it is valid */
946                 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
947                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
948                 client->lease->t1 = client->lease->lifetime / 2;
949                 if (t2_timeout <= t1_timeout) {
950                         /* the computed T1 would be invalid, so discard T2 */
951                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
952                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
953                 }
954         } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
955                 /* only T1 is given, and it is valid */
956                 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
957                 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
958                 client->lease->t2 = (client->lease->lifetime * 7) / 8;
959                 if (t2_timeout <= t1_timeout) {
960                         /* the computed T2 would be invalid, so discard T1 */
961                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
962                         client->lease->t2 = client->lease->lifetime / 2;
963                 }
964         } else {
965                 /* fall back to the default timeouts */
966                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
967                 client->lease->t1 = client->lease->lifetime / 2;
968                 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
969                 client->lease->t2 = (client->lease->lifetime * 7) / 8;
970         }
971
972         /* arm lifetime timeout */
973         r = sd_event_add_time(client->event, &client->timeout_expire,
974                               CLOCK_MONOTONIC,
975                               lifetime_timeout, 10 * USEC_PER_MSEC,
976                               client_timeout_expire, client);
977         if (r < 0)
978                 return r;
979
980         r = sd_event_source_set_priority(client->timeout_expire,
981                                          client->event_priority);
982         if (r < 0)
983                 return r;
984
985         log_dhcp_client(client, "lease expires in %s",
986                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
987                         lifetime_timeout - time_now, 0));
988
989         /* don't arm earlier timeouts if this has already expired */
990         if (lifetime_timeout <= time_now)
991                 return 0;
992
993         /* arm T2 timeout */
994         r = sd_event_add_time(client->event,
995                               &client->timeout_t2,
996                               CLOCK_MONOTONIC,
997                               t2_timeout,
998                               10 * USEC_PER_MSEC,
999                               client_timeout_t2, client);
1000         if (r < 0)
1001                 return r;
1002
1003         r = sd_event_source_set_priority(client->timeout_t2,
1004                                          client->event_priority);
1005         if (r < 0)
1006                 return r;
1007
1008         log_dhcp_client(client, "T2 expires in %s",
1009                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1010                         t2_timeout - time_now, 0));
1011
1012         /* don't arm earlier timeout if this has already expired */
1013         if (t2_timeout <= time_now)
1014                 return 0;
1015
1016         /* arm T1 timeout */
1017         r = sd_event_add_time(client->event,
1018                               &client->timeout_t1,
1019                               CLOCK_MONOTONIC,
1020                               t1_timeout, 10 * USEC_PER_MSEC,
1021                               client_timeout_t1, client);
1022         if (r < 0)
1023                 return r;
1024
1025         r = sd_event_source_set_priority(client->timeout_t1,
1026                                          client->event_priority);
1027         if (r < 0)
1028                 return r;
1029
1030         log_dhcp_client(client, "T1 expires in %s",
1031                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1032                         t1_timeout - time_now, 0));
1033
1034         return 0;
1035 }
1036
1037 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1038                                  int len) {
1039         int r = 0, notify_event = 0;
1040
1041         assert(client);
1042         assert(client->event);
1043         assert(message);
1044
1045         if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1046                 log_dhcp_client(client, "not a DHCP message: ignoring");
1047                 return 0;
1048         }
1049
1050         if (message->op != BOOTREPLY) {
1051                 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1052                 return 0;
1053         }
1054
1055         if (be32toh(message->xid) != client->xid) {
1056                 log_dhcp_client(client, "received xid (%u) does not match "
1057                                 "expected (%u): ignoring",
1058                                 be32toh(message->xid), client->xid);
1059                 return 0;
1060         }
1061
1062         if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1063                 log_dhcp_client(client, "not an ethernet packet");
1064                 return 0;
1065         }
1066
1067         if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1068                    ETH_ALEN)) {
1069                 log_dhcp_client(client, "received chaddr does not match "
1070                                 "expected: ignoring");
1071                 return 0;
1072         }
1073
1074         switch (client->state) {
1075         case DHCP_STATE_SELECTING:
1076
1077                 r = client_handle_offer(client, message, len);
1078                 if (r >= 0) {
1079
1080                         client->timeout_resend =
1081                                 sd_event_source_unref(client->timeout_resend);
1082
1083                         client->state = DHCP_STATE_REQUESTING;
1084                         client->attempt = 1;
1085
1086                         r = sd_event_add_time(client->event,
1087                                               &client->timeout_resend,
1088                                               CLOCK_MONOTONIC,
1089                                               0, 0,
1090                                               client_timeout_resend, client);
1091                         if (r < 0)
1092                                 goto error;
1093
1094                         r = sd_event_source_set_priority(client->timeout_resend,
1095                                                          client->event_priority);
1096                         if (r < 0)
1097                                 goto error;
1098                 } else if (r == -ENOMSG)
1099                         /* invalid message, let's ignore it */
1100                         return 0;
1101
1102                 break;
1103
1104         case DHCP_STATE_REBOOTING:
1105         case DHCP_STATE_REQUESTING:
1106         case DHCP_STATE_RENEWING:
1107         case DHCP_STATE_REBINDING:
1108
1109                 r = client_handle_ack(client, message, len);
1110                 if (r == DHCP_EVENT_NO_LEASE) {
1111
1112                         client->timeout_resend =
1113                                 sd_event_source_unref(client->timeout_resend);
1114
1115                         if (client->state == DHCP_STATE_REBOOTING) {
1116                                 r = client_initialize(client);
1117                                 if (r < 0)
1118                                         goto error;
1119
1120                                 r = client_start(client);
1121                                 if (r < 0)
1122                                         goto error;
1123
1124                                 log_dhcp_client(client, "REBOOTED");
1125                         }
1126
1127                         goto error;
1128                 } else if (r >= 0) {
1129                         client->timeout_resend =
1130                                 sd_event_source_unref(client->timeout_resend);
1131
1132                         if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1133                                    DHCP_STATE_REBOOTING))
1134                                 notify_event = DHCP_EVENT_IP_ACQUIRE;
1135                         else if (r != DHCP_EVENT_IP_ACQUIRE)
1136                                 notify_event = r;
1137
1138                         client->state = DHCP_STATE_BOUND;
1139                         client->attempt = 1;
1140
1141                         client->last_addr = client->lease->address;
1142
1143                         r = client_set_lease_timeouts(client);
1144                         if (r < 0)
1145                                 goto error;
1146
1147                         if (notify_event) {
1148                                 client = client_notify(client, notify_event);
1149                                 if (!client ||
1150                                     client->state == DHCP_STATE_STOPPED)
1151                                         return 0;
1152                         }
1153
1154                         client->receive_message =
1155                                 sd_event_source_unref(client->receive_message);
1156                         client->fd = safe_close(client->fd);
1157                 } else if (r == -ENOMSG)
1158                         /* invalid message, let's ignore it */
1159                         return 0;
1160
1161                 break;
1162
1163         case DHCP_STATE_INIT:
1164         case DHCP_STATE_INIT_REBOOT:
1165         case DHCP_STATE_BOUND:
1166
1167                 break;
1168
1169         case DHCP_STATE_STOPPED:
1170                 r = -EINVAL;
1171                 goto error;
1172         }
1173
1174 error:
1175         if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1176                 client_stop(client, r);
1177
1178         return r;
1179 }
1180
1181 static int client_receive_message_udp(sd_event_source *s, int fd,
1182                                       uint32_t revents, void *userdata) {
1183         sd_dhcp_client *client = userdata;
1184         _cleanup_free_ DHCPMessage *message = NULL;
1185         int buflen = 0, len, r;
1186
1187         assert(s);
1188         assert(client);
1189
1190         r = ioctl(fd, FIONREAD, &buflen);
1191         if (r < 0 || buflen <= 0)
1192                 buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE;
1193
1194         message = malloc0(buflen);
1195         if (!message)
1196                 return -ENOMEM;
1197
1198         len = read(fd, message, buflen);
1199         if (len < 0) {
1200                 log_dhcp_client(client, "could not receive message from UDP "
1201                                 "socket: %s", strerror(errno));
1202                 return 0;
1203         } else if ((size_t)len < sizeof(DHCPMessage))
1204                 return 0;
1205
1206         return client_handle_message(client, message, len);
1207 }
1208
1209 static int client_receive_message_raw(sd_event_source *s, int fd,
1210                                       uint32_t revents, void *userdata) {
1211         sd_dhcp_client *client = userdata;
1212         _cleanup_free_ DHCPPacket *packet = NULL;
1213         uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1214         struct iovec iov = {};
1215         struct msghdr msg = {
1216                 .msg_iov = &iov,
1217                 .msg_iovlen = 1,
1218                 .msg_control = cmsgbuf,
1219                 .msg_controllen = sizeof(cmsgbuf),
1220         };
1221         struct cmsghdr *cmsg;
1222         bool checksum = true;
1223         int buflen = 0, len, r;
1224
1225         assert(s);
1226         assert(client);
1227
1228         r = ioctl(fd, FIONREAD, &buflen);
1229         if (r < 0 || buflen <= 0)
1230                 buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE;
1231
1232         packet = malloc0(buflen);
1233         if (!packet)
1234                 return -ENOMEM;
1235
1236         iov.iov_base = packet;
1237         iov.iov_len = buflen;
1238
1239         len = recvmsg(fd, &msg, 0);
1240         if (len < 0) {
1241                 log_dhcp_client(client, "could not receive message from raw "
1242                                 "socket: %s", strerror(errno));
1243                 return 0;
1244         } else if ((size_t)len < sizeof(DHCPPacket))
1245                 return 0;
1246
1247         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1248                 if (cmsg->cmsg_level == SOL_PACKET &&
1249                     cmsg->cmsg_type == PACKET_AUXDATA &&
1250                     cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1251                         struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1252
1253                         checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1254                         break;
1255                 }
1256         }
1257
1258         r = dhcp_packet_verify_headers(packet, len, checksum);
1259         if (r < 0)
1260                 return 0;
1261
1262         len -= DHCP_IP_UDP_SIZE;
1263
1264         return client_handle_message(client, &packet->dhcp, len);
1265 }
1266
1267 int sd_dhcp_client_start(sd_dhcp_client *client) {
1268         int r;
1269
1270         assert_return(client, -EINVAL);
1271
1272         r = client_initialize(client);
1273         if (r < 0)
1274                 return r;
1275
1276         if (client->last_addr)
1277                 client->state = DHCP_STATE_INIT_REBOOT;
1278
1279         r = client_start(client);
1280         if (r >= 0)
1281                 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1282                                 client->index,
1283                                 ether_ntoa(&client->client_id.mac_addr));
1284
1285         return r;
1286 }
1287
1288 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1289         assert_return(client, -EINVAL);
1290
1291         if (client_stop(client, DHCP_EVENT_STOP))
1292                 client->state = DHCP_STATE_STOPPED;
1293
1294         return 0;
1295 }
1296
1297 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1298                                 int priority) {
1299         int r;
1300
1301         assert_return(client, -EINVAL);
1302         assert_return(!client->event, -EBUSY);
1303
1304         if (event)
1305                 client->event = sd_event_ref(event);
1306         else {
1307                 r = sd_event_default(&client->event);
1308                 if (r < 0)
1309                         return 0;
1310         }
1311
1312         client->event_priority = priority;
1313
1314         return 0;
1315 }
1316
1317 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1318         assert_return(client, -EINVAL);
1319
1320         client->event = sd_event_unref(client->event);
1321
1322         return 0;
1323 }
1324
1325 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1326         if (!client)
1327                 return NULL;
1328
1329         return client->event;
1330 }
1331
1332 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1333         if (client)
1334                 assert_se(REFCNT_INC(client->n_ref) >= 2);
1335
1336         return client;
1337 }
1338
1339 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1340         if (client && REFCNT_DEC(client->n_ref) <= 0) {
1341                 log_dhcp_client(client, "UNREF");
1342
1343                 client_initialize(client);
1344
1345                 client->receive_message =
1346                         sd_event_source_unref(client->receive_message);
1347
1348                 sd_dhcp_client_detach_event(client);
1349
1350                 sd_dhcp_lease_unref(client->lease);
1351
1352                 free(client->req_opts);
1353                 free(client);
1354
1355                 return NULL;
1356         }
1357
1358         return client;
1359 }
1360
1361 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
1362 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1363
1364 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1365         _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1366
1367         assert_return(ret, -EINVAL);
1368
1369         client = new0(sd_dhcp_client, 1);
1370         if (!client)
1371                 return -ENOMEM;
1372
1373         client->n_ref = REFCNT_INIT;
1374         client->state = DHCP_STATE_INIT;
1375         client->index = -1;
1376         client->fd = -1;
1377         client->attempt = 1;
1378
1379         client->req_opts_size = ELEMENTSOF(default_req_opts);
1380
1381         client->req_opts = memdup(default_req_opts, client->req_opts_size);
1382         if (!client->req_opts)
1383                 return -ENOMEM;
1384
1385         *ret = client;
1386         client = NULL;
1387
1388         return 0;
1389 }