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