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