chiark / gitweb /
7dc154612816ac3902070cce9bbecdba76efe5f4
[elogind.git] / src / libsystemd-dhcp / 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
26 #include "util.h"
27 #include "list.h"
28
29 #include "dhcp-protocol.h"
30 #include "dhcp-internal.h"
31 #include "sd-dhcp-client.h"
32
33 #define DHCP_CLIENT_MIN_OPTIONS_SIZE            312
34
35 struct DHCPLease {
36         uint32_t t1;
37         uint32_t t2;
38         uint32_t lifetime;
39         be32_t address;
40         be32_t server_address;
41         be32_t subnet_mask;
42         be32_t router;
43 };
44
45 typedef struct DHCPLease DHCPLease;
46
47 struct sd_dhcp_client {
48         DHCPState state;
49         sd_event *event;
50         sd_event_source *timeout_resend;
51         int index;
52         int fd;
53         union sockaddr_union link;
54         sd_event_source *receive_message;
55         uint8_t *req_opts;
56         size_t req_opts_size;
57         be32_t last_addr;
58         struct ether_addr mac_addr;
59         uint32_t xid;
60         usec_t start_time;
61         unsigned int attempt;
62         usec_t request_sent;
63         sd_event_source *timeout_t1;
64         sd_event_source *timeout_t2;
65         sd_event_source *timeout_expire;
66         sd_dhcp_client_cb_t cb;
67         void *userdata;
68         DHCPLease *lease;
69 };
70
71 static const uint8_t default_req_opts[] = {
72         DHCP_OPTION_SUBNET_MASK,
73         DHCP_OPTION_ROUTER,
74         DHCP_OPTION_HOST_NAME,
75         DHCP_OPTION_DOMAIN_NAME,
76         DHCP_OPTION_DOMAIN_NAME_SERVER,
77         DHCP_OPTION_NTP_SERVER,
78 };
79
80 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
81                                 void *userdata)
82 {
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 {
93         size_t i;
94
95         assert_return(client, -EINVAL);
96         assert_return (client->state == DHCP_STATE_INIT, -EBUSY);
97
98         switch(option) {
99         case DHCP_OPTION_PAD:
100         case DHCP_OPTION_OVERLOAD:
101         case DHCP_OPTION_MESSAGE_TYPE:
102         case DHCP_OPTION_PARAMETER_REQUEST_LIST:
103         case DHCP_OPTION_END:
104                 return -EINVAL;
105
106         default:
107                 break;
108         }
109
110         for (i = 0; i < client->req_opts_size; i++)
111                 if (client->req_opts[i] == option)
112                         return -EEXIST;
113
114         if (!GREEDY_REALLOC(client->req_opts, client->req_opts_size,
115                             client->req_opts_size + 1))
116                 return -ENOMEM;
117
118         client->req_opts[client->req_opts_size - 1] = option;
119
120         return 0;
121 }
122
123 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
124                                        const struct in_addr *last_addr)
125 {
126         assert_return(client, -EINVAL);
127         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
128
129         if (last_addr)
130                 client->last_addr = last_addr->s_addr;
131         else
132                 client->last_addr = INADDR_ANY;
133
134         return 0;
135 }
136
137 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index)
138 {
139         assert_return(client, -EINVAL);
140         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
141         assert_return(interface_index >= -1, -EINVAL);
142
143         client->index = interface_index;
144
145         return 0;
146 }
147
148 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
149                            const struct ether_addr *addr)
150 {
151         assert_return(client, -EINVAL);
152         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
153
154         memcpy(&client->mac_addr, addr, ETH_ALEN);
155
156         return 0;
157 }
158
159 int sd_dhcp_client_get_address(sd_dhcp_client *client, struct in_addr *addr)
160 {
161         assert_return(client, -EINVAL);
162         assert_return(addr, -EINVAL);
163
164         switch (client->state) {
165         case DHCP_STATE_INIT:
166         case DHCP_STATE_SELECTING:
167         case DHCP_STATE_INIT_REBOOT:
168         case DHCP_STATE_REBOOTING:
169         case DHCP_STATE_REQUESTING:
170                 return -EADDRNOTAVAIL;
171
172         case DHCP_STATE_BOUND:
173         case DHCP_STATE_RENEWING:
174         case DHCP_STATE_REBINDING:
175                 addr->s_addr = client->lease->address;
176
177                 break;
178         }
179
180         return 0;
181 }
182
183 int sd_dhcp_client_get_netmask(sd_dhcp_client *client, struct in_addr *addr)
184 {
185         assert_return(client, -EINVAL);
186         assert_return(addr, -EINVAL);
187
188         switch (client->state) {
189         case DHCP_STATE_INIT:
190         case DHCP_STATE_SELECTING:
191         case DHCP_STATE_INIT_REBOOT:
192         case DHCP_STATE_REBOOTING:
193         case DHCP_STATE_REQUESTING:
194                 return -EADDRNOTAVAIL;
195
196         case DHCP_STATE_BOUND:
197         case DHCP_STATE_RENEWING:
198         case DHCP_STATE_REBINDING:
199                 addr->s_addr = client->lease->subnet_mask;
200
201                 break;
202         }
203
204         return 0;
205 }
206
207 int sd_dhcp_client_prefixlen(const struct in_addr *addr)
208 {
209         int len = 0;
210         uint32_t mask;
211
212         assert_return(addr, -EADDRNOTAVAIL);
213
214         mask = be32toh(addr->s_addr);
215         while (mask) {
216                 len++;
217                 mask = mask << 1;
218         }
219
220         return len;
221 }
222
223 int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr)
224 {
225         assert_return(client, -EINVAL);
226         assert_return(addr, -EINVAL);
227
228         switch (client->state) {
229         case DHCP_STATE_INIT:
230         case DHCP_STATE_SELECTING:
231         case DHCP_STATE_INIT_REBOOT:
232         case DHCP_STATE_REBOOTING:
233         case DHCP_STATE_REQUESTING:
234                 return -EADDRNOTAVAIL;
235
236         case DHCP_STATE_BOUND:
237         case DHCP_STATE_RENEWING:
238         case DHCP_STATE_REBINDING:
239                 addr->s_addr = client->lease->router;
240
241                 break;
242         }
243
244         return 0;
245 }
246
247 static int client_notify(sd_dhcp_client *client, int event)
248 {
249         if (client->cb)
250                 client->cb(client, event, client->userdata);
251
252         return 0;
253 }
254
255 static int client_stop(sd_dhcp_client *client, int error)
256 {
257         assert_return(client, -EINVAL);
258         assert_return(client->state != DHCP_STATE_INIT &&
259                       client->state != DHCP_STATE_INIT_REBOOT, -EALREADY);
260
261         client->receive_message =
262                 sd_event_source_unref(client->receive_message);
263
264         if (client->fd >= 0)
265                 close(client->fd);
266         client->fd = -1;
267
268         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
269
270         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
271         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
272         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
273
274         client->attempt = 1;
275
276         client_notify(client, error);
277
278         switch (client->state) {
279
280         case DHCP_STATE_INIT:
281         case DHCP_STATE_SELECTING:
282         case DHCP_STATE_REQUESTING:
283         case DHCP_STATE_BOUND:
284
285                 client->start_time = 0;
286                 client->state = DHCP_STATE_INIT;
287                 break;
288
289         case DHCP_STATE_INIT_REBOOT:
290         case DHCP_STATE_REBOOTING:
291         case DHCP_STATE_RENEWING:
292         case DHCP_STATE_REBINDING:
293
294                 break;
295         }
296
297         if (client->lease) {
298                 free(client->lease);
299                 client->lease = NULL;
300         }
301
302         return 0;
303 }
304
305 static int client_packet_init(sd_dhcp_client *client, uint8_t type,
306                               DHCPMessage *message, uint16_t secs,
307                               uint8_t **opt, size_t *optlen)
308 {
309         int err;
310         be16_t max_size;
311
312         *opt = (uint8_t *)(message + 1);
313
314         if (*optlen < 4)
315                 return -ENOBUFS;
316         *optlen -= 4;
317
318         message->op = BOOTREQUEST;
319         message->htype = 1;
320         message->hlen = ETHER_ADDR_LEN;
321         message->xid = htobe32(client->xid);
322
323         /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
324            refuse to issue an DHCP lease if 'secs' is set to zero */
325         message->secs = htobe16(secs);
326
327         memcpy(&message->chaddr, &client->mac_addr, ETH_ALEN);
328         (*opt)[0] = 0x63;
329         (*opt)[1] = 0x82;
330         (*opt)[2] = 0x53;
331         (*opt)[3] = 0x63;
332
333         *opt += 4;
334
335         err = dhcp_option_append(opt, optlen, DHCP_OPTION_MESSAGE_TYPE, 1,
336                                  &type);
337         if (err < 0)
338                 return err;
339
340         /* Some DHCP servers will refuse to issue an DHCP lease if the Cliient
341            Identifier option is not set */
342         err = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
343                                  ETH_ALEN, &client->mac_addr);
344         if (err < 0)
345                 return err;
346
347         if (type == DHCP_DISCOVER || type == DHCP_REQUEST) {
348                 err = dhcp_option_append(opt, optlen,
349                                          DHCP_OPTION_PARAMETER_REQUEST_LIST,
350                                          client->req_opts_size,
351                                          client->req_opts);
352                 if (err < 0)
353                         return err;
354
355                 /* Some DHCP servers will send bigger DHCP packets than the
356                    defined default size unless the Maximum Messge Size option
357                    is explicitely set */
358                 max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
359                                    DHCP_CLIENT_MIN_OPTIONS_SIZE);
360                 err = dhcp_option_append(opt, optlen,
361                                          DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
362                                          2, &max_size);
363                 if (err < 0)
364                         return err;
365         }
366
367         return 0;
368 }
369
370 static uint16_t client_checksum(void *buf, int len)
371 {
372         uint32_t sum;
373         uint16_t *check;
374         int i;
375         uint8_t *odd;
376
377         sum = 0;
378         check = buf;
379
380         for (i = 0; i < len / 2 ; i++)
381                 sum += check[i];
382
383         if (len & 0x01) {
384                 odd = buf;
385                 sum += odd[len];
386         }
387
388         return ~((sum & 0xffff) + (sum >> 16));
389 }
390
391 static void client_append_ip_headers(DHCPPacket *packet, uint16_t len)
392 {
393         packet->ip.version = IPVERSION;
394         packet->ip.ihl = DHCP_IP_SIZE / 4;
395         packet->ip.tot_len = htobe16(len);
396
397         packet->ip.protocol = IPPROTO_UDP;
398         packet->ip.saddr = INADDR_ANY;
399         packet->ip.daddr = INADDR_BROADCAST;
400
401         packet->udp.source = htobe16(DHCP_PORT_CLIENT);
402         packet->udp.dest = htobe16(DHCP_PORT_SERVER);
403         packet->udp.len = htobe16(len - DHCP_IP_SIZE);
404
405         packet->ip.check = packet->udp.len;
406         packet->udp.check = client_checksum(&packet->ip.ttl, len - 8);
407
408         packet->ip.ttl = IPDEFTTL;
409         packet->ip.check = 0;
410         packet->ip.check = client_checksum(&packet->ip, DHCP_IP_SIZE);
411 }
412
413 static int client_send_discover(sd_dhcp_client *client, uint16_t secs)
414 {
415         int err = 0;
416         _cleanup_free_ DHCPPacket *discover;
417         size_t optlen, len;
418         uint8_t *opt;
419
420         optlen = DHCP_CLIENT_MIN_OPTIONS_SIZE;
421         len = sizeof(DHCPPacket) + optlen;
422
423         discover = malloc0(len);
424
425         if (!discover)
426                 return -ENOMEM;
427
428         err = client_packet_init(client, DHCP_DISCOVER, &discover->dhcp,
429                                  secs, &opt, &optlen);
430         if (err < 0)
431                 return err;
432
433         if (client->last_addr != INADDR_ANY) {
434                 err = dhcp_option_append(&opt, &optlen,
435                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
436                                          4, &client->last_addr);
437                 if (err < 0)
438                         return err;
439         }
440
441         err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
442         if (err < 0)
443                 return err;
444
445         client_append_ip_headers(discover, len);
446
447         err = dhcp_network_send_raw_socket(client->fd, &client->link,
448                                            discover, len);
449
450         return err;
451 }
452
453 static int client_send_request(sd_dhcp_client *client, uint16_t secs)
454 {
455         _cleanup_free_ DHCPPacket *request;
456         size_t optlen, len;
457         int err;
458         uint8_t *opt;
459
460         optlen = DHCP_CLIENT_MIN_OPTIONS_SIZE;
461         len = DHCP_MESSAGE_SIZE + optlen;
462
463         request = malloc0(len);
464         if (!request)
465                 return -ENOMEM;
466
467         err = client_packet_init(client, DHCP_REQUEST, &request->dhcp, secs,
468                                  &opt, &optlen);
469         if (err < 0)
470                 return err;
471
472         if (client->state == DHCP_STATE_REQUESTING) {
473                 err = dhcp_option_append(&opt, &optlen,
474                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
475                                          4, &client->lease->address);
476                 if (err < 0)
477                         return err;
478
479                 err = dhcp_option_append(&opt, &optlen,
480                                          DHCP_OPTION_SERVER_IDENTIFIER,
481                                          4, &client->lease->server_address);
482                 if (err < 0)
483                         return err;
484         }
485
486         err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
487         if (err < 0)
488                 return err;
489
490         client_append_ip_headers(request, len);
491
492         err = dhcp_network_send_raw_socket(client->fd, &client->link,
493                                            request, len);
494
495         return err;
496 }
497
498 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
499                                  void *userdata)
500 {
501         sd_dhcp_client *client = userdata;
502         usec_t next_timeout;
503         uint16_t secs;
504         int err = 0;
505
506         secs = (usec - client->start_time) / USEC_PER_SEC;
507
508         if (client->attempt < 64)
509                 client->attempt *= 2;
510
511         next_timeout = usec + (client->attempt - 1) * USEC_PER_SEC +
512                 (random_u() & 0x1fffff);
513
514         err = sd_event_add_monotonic(client->event, next_timeout,
515                                      10 * USEC_PER_MSEC,
516                                      client_timeout_resend, client,
517                                      &client->timeout_resend);
518         if (err < 0)
519                 goto error;
520
521         switch (client->state) {
522         case DHCP_STATE_INIT:
523                 err = client_send_discover(client, secs);
524                 if (err >= 0) {
525                         client->state = DHCP_STATE_SELECTING;
526                         client->attempt = 1;
527                 } else {
528                         if (client->attempt >= 64)
529                                 goto error;
530                 }
531
532                 break;
533
534         case DHCP_STATE_SELECTING:
535                 err = client_send_discover(client, secs);
536                 if (err < 0 && client->attempt >= 64)
537                         goto error;
538
539                 break;
540
541         case DHCP_STATE_REQUESTING:
542                 err = client_send_request(client, secs);
543                 if (err < 0 && client->attempt >= 64)
544                          goto error;
545
546                 client->request_sent = usec;
547
548                 break;
549
550         case DHCP_STATE_INIT_REBOOT:
551         case DHCP_STATE_REBOOTING:
552         case DHCP_STATE_BOUND:
553         case DHCP_STATE_RENEWING:
554         case DHCP_STATE_REBINDING:
555
556                 break;
557         }
558
559         return 0;
560
561 error:
562         client_stop(client, err);
563
564         /* Errors were dealt with when stopping the client, don't spill
565            errors into the event loop handler */
566         return 0;
567 }
568
569 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
570                                  void *userdata)
571 {
572         sd_dhcp_client *client = userdata;
573
574         client_stop(client, DHCP_EVENT_EXPIRED);
575
576         return 0;
577 }
578
579 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
580 {
581         return 0;
582 }
583
584 static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
585 {
586         return 0;
587 }
588
589 static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
590                               void *user_data)
591 {
592         DHCPLease *lease = user_data;
593         be32_t val;
594
595         switch(code) {
596
597         case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
598                 if (len == 4) {
599                         memcpy(&val, option, 4);
600                         lease->lifetime = be32toh(val);
601                 }
602
603                 break;
604
605         case DHCP_OPTION_SERVER_IDENTIFIER:
606                 if (len >= 4)
607                         memcpy(&lease->server_address, option, 4);
608
609                 break;
610
611         case DHCP_OPTION_SUBNET_MASK:
612                 if (len >= 4)
613                         memcpy(&lease->subnet_mask, option, 4);
614
615                 break;
616
617         case DHCP_OPTION_ROUTER:
618                 if (len >= 4)
619                         memcpy(&lease->router, option, 4);
620
621                 break;
622
623         case DHCP_OPTION_RENEWAL_T1_TIME:
624                 if (len == 4) {
625                         memcpy(&val, option, 4);
626                         lease->t1 = be32toh(val);
627                 }
628
629                 break;
630
631         case DHCP_OPTION_REBINDING_T2_TIME:
632                 if (len == 4) {
633                         memcpy(&val, option, 4);
634                         lease->t2 = be32toh(val);
635                 }
636
637                 break;
638         }
639
640         return 0;
641 }
642
643 static int client_verify_headers(sd_dhcp_client *client, DHCPPacket *message,
644                                  size_t len)
645 {
646         size_t hdrlen;
647
648         if (len < (DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE))
649                 return -EINVAL;
650
651         hdrlen = message->ip.ihl * 4;
652         if (hdrlen < 20 || hdrlen > len || client_checksum(&message->ip,
653                                                            hdrlen))
654                 return -EINVAL;
655
656         message->ip.check = message->udp.len;
657         message->ip.ttl = 0;
658
659         if (hdrlen + be16toh(message->udp.len) > len ||
660             client_checksum(&message->ip.ttl, be16toh(message->udp.len) + 12))
661                 return -EINVAL;
662
663         if (be16toh(message->udp.source) != DHCP_PORT_SERVER ||
664             be16toh(message->udp.dest) != DHCP_PORT_CLIENT)
665                 return -EINVAL;
666
667         if (message->dhcp.op != BOOTREPLY)
668                 return -EINVAL;
669
670         if (be32toh(message->dhcp.xid) != client->xid)
671                 return -EINVAL;
672
673         if (memcmp(&message->dhcp.chaddr[0], &client->mac_addr.ether_addr_octet,
674                     ETHER_ADDR_LEN))
675                 return -EINVAL;
676
677         return 0;
678 }
679
680 static int client_receive_offer(sd_dhcp_client *client, DHCPPacket *offer,
681                                 size_t len)
682 {
683         int err;
684         DHCPLease *lease;
685
686         err = client_verify_headers(client, offer, len);
687         if (err < 0)
688                 return err;
689
690         lease = new0(DHCPLease, 1);
691         if (!lease)
692                 return -ENOMEM;
693
694         len = len - DHCP_IP_UDP_SIZE;
695         if (dhcp_option_parse(&offer->dhcp, len, client_parse_offer,
696                               lease) != DHCP_OFFER)
697                 goto error;
698
699         lease->address = offer->dhcp.yiaddr;
700
701         if (lease->address == INADDR_ANY ||
702             lease->server_address == INADDR_ANY ||
703             lease->subnet_mask == INADDR_ANY ||
704             lease->lifetime == 0)
705                 goto error;
706
707         client->lease = lease;
708
709         return 0;
710
711 error:
712         free(lease);
713
714         return -ENOMSG;
715 }
716
717 static int client_receive_ack(sd_dhcp_client *client, DHCPPacket *offer,
718                               size_t len)
719 {
720         int r;
721         DHCPLease *lease;
722
723         r = client_verify_headers(client, offer, len);
724         if (r < 0)
725                 return r;
726
727         lease = new0(DHCPLease, 1);
728         if (!lease)
729                 return -ENOMEM;
730
731         len = len - DHCP_IP_UDP_SIZE;
732         r = dhcp_option_parse(&offer->dhcp, len, client_parse_offer, lease);
733
734         if (r == DHCP_NAK) {
735                 r = DHCP_EVENT_NO_LEASE;
736                 goto error;
737         }
738
739         if (r != DHCP_ACK) {
740                 r = -ENOMSG;
741                 goto error;
742         }
743
744         lease->address = offer->dhcp.yiaddr;
745
746         if (lease->address == INADDR_ANY ||
747             lease->server_address == INADDR_ANY ||
748             lease->subnet_mask == INADDR_ANY || lease->lifetime == 0) {
749                 r = -ENOMSG;
750                 goto error;
751         }
752
753         r = DHCP_EVENT_IP_ACQUIRE;
754         if (client->lease) {
755                 if (client->lease->address != lease->address ||
756                     client->lease->subnet_mask != lease->subnet_mask ||
757                     client->lease->router != lease->router) {
758                         r = DHCP_EVENT_IP_CHANGE;
759                 }
760
761                 free(client->lease);
762         }
763
764         client->lease = lease;
765
766         return r;
767
768 error:
769         free(lease);
770
771         return r;
772 }
773
774 static uint64_t client_compute_timeout(uint64_t request_sent,
775                                        uint32_t lifetime)
776 {
777         return request_sent + (lifetime - 3) * USEC_PER_SEC +
778                 + (random_u() & 0x1fffff);
779 }
780
781 static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec)
782 {
783         int err;
784         uint64_t next_timeout;
785
786         if (client->lease->lifetime < 10)
787                 return -EINVAL;
788
789         if (!client->lease->t1)
790                 client->lease->t1 = client->lease->lifetime / 2;
791
792         next_timeout = client_compute_timeout(client->request_sent,
793                                               client->lease->t1);
794         if (next_timeout < usec)
795                 return -EINVAL;
796
797         err = sd_event_add_monotonic(client->event, next_timeout,
798                                      10 * USEC_PER_MSEC,
799                                      client_timeout_t1, client,
800                                      &client->timeout_t1);
801         if (err < 0)
802                 return err;
803
804         if (!client->lease->t2)
805                 client->lease->t2 = client->lease->lifetime * 7 / 8;
806
807         if (client->lease->t2 < client->lease->t1)
808                 return -EINVAL;
809
810         if (client->lease->lifetime < client->lease->t2)
811                 return -EINVAL;
812
813         next_timeout = client_compute_timeout(client->request_sent,
814                                               client->lease->t2);
815         if (next_timeout < usec)
816                 return -EINVAL;
817
818         err = sd_event_add_monotonic(client->event, next_timeout,
819                                      10 * USEC_PER_MSEC,
820                                      client_timeout_t2, client,
821                                      &client->timeout_t2);
822         if (err < 0)
823                 return err;
824
825         next_timeout = client_compute_timeout(client->request_sent,
826                                               client->lease->lifetime);
827         if (next_timeout < usec)
828                 return -EINVAL;
829
830         err = sd_event_add_monotonic(client->event, next_timeout,
831                                      10 * USEC_PER_MSEC,
832                                      client_timeout_expire, client,
833                                      &client->timeout_expire);
834         if (err < 0)
835                 return err;
836
837         return 0;
838 }
839
840 static int client_receive_raw_message(sd_event_source *s, int fd,
841                                       uint32_t revents, void *userdata)
842 {
843         sd_dhcp_client *client = userdata;
844         uint8_t buf[sizeof(DHCPPacket) + DHCP_CLIENT_MIN_OPTIONS_SIZE];
845         int buflen = sizeof(buf);
846         int len, r = 0;
847         DHCPPacket *message;
848         usec_t time_now;
849
850         len = read(fd, &buf, buflen);
851         if (len < 0)
852                 return 0;
853
854         r = sd_event_get_now_monotonic(client->event, &time_now);
855         if (r < 0)
856                 goto error;
857
858         message = (DHCPPacket *)&buf;
859
860         switch (client->state) {
861         case DHCP_STATE_SELECTING:
862
863                 if (client_receive_offer(client, message, len) >= 0) {
864
865                         client->timeout_resend =
866                                 sd_event_source_unref(client->timeout_resend);
867
868                         client->state = DHCP_STATE_REQUESTING;
869                         client->attempt = 1;
870
871                         r = sd_event_add_monotonic(client->event, time_now, 0,
872                                                    client_timeout_resend,
873                                                    client,
874                                                    &client->timeout_resend);
875                         if (r < 0)
876                                 goto error;
877                 }
878
879                 break;
880
881         case DHCP_STATE_REQUESTING:
882
883                 r = client_receive_ack(client, message, len);
884                 if (r == DHCP_EVENT_NO_LEASE)
885                         goto error;
886
887                 if (r >= 0) {
888                         client->timeout_resend =
889                                 sd_event_source_unref(client->timeout_resend);
890
891                         client->state = DHCP_STATE_BOUND;
892                         client->attempt = 1;
893
894                         client->last_addr = client->lease->address;
895
896                         r = client_set_lease_timeouts(client, time_now);
897                         if (r < 0 )
898                                 goto error;
899
900                         client_notify(client, DHCP_EVENT_IP_ACQUIRE);
901
902                         client->receive_message =
903                                 sd_event_source_unref(client->receive_message);
904                         close(client->fd);
905                         client->fd = -1;
906                 }
907
908                 r = 0;
909
910                 break;
911
912         case DHCP_STATE_INIT:
913         case DHCP_STATE_INIT_REBOOT:
914         case DHCP_STATE_REBOOTING:
915         case DHCP_STATE_BOUND:
916         case DHCP_STATE_RENEWING:
917         case DHCP_STATE_REBINDING:
918
919                 break;
920         }
921
922 error:
923         if (r < 0 || r == DHCP_EVENT_NO_LEASE)
924                 return client_stop(client, r);
925
926         return 0;
927 }
928
929 int sd_dhcp_client_start(sd_dhcp_client *client)
930 {
931         int err;
932
933         assert_return(client, -EINVAL);
934         assert_return(client->index >= 0, -EINVAL);
935         assert_return(client->state == DHCP_STATE_INIT ||
936                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
937
938         client->xid = random_u();
939
940         client->fd = dhcp_network_bind_raw_socket(client->index,
941                                                   &client->link);
942
943         if (client->fd < 0) {
944                 err = client->fd;
945                 goto error;
946         }
947
948         err = sd_event_add_io(client->event, client->fd, EPOLLIN,
949                               client_receive_raw_message, client,
950                               &client->receive_message);
951         if (err < 0)
952                 goto error;
953
954         client->start_time = now(CLOCK_MONOTONIC);
955         err = sd_event_add_monotonic(client->event, client->start_time, 0,
956                                      client_timeout_resend, client,
957                                      &client->timeout_resend);
958         if (err < 0)
959                 goto error;
960
961         return 0;
962
963 error:
964         client_stop(client, err);
965
966         return err;
967 }
968
969 int sd_dhcp_client_stop(sd_dhcp_client *client)
970 {
971         return client_stop(client, DHCP_EVENT_STOP);
972 }
973
974 sd_dhcp_client *sd_dhcp_client_free(sd_dhcp_client *client)
975 {
976         assert_return(client, NULL);
977
978         sd_dhcp_client_stop(client);
979
980         sd_event_unref(client->event);
981         free(client->req_opts);
982         free(client);
983
984         return NULL;
985 }
986
987 sd_dhcp_client *sd_dhcp_client_new(sd_event *event)
988 {
989         sd_dhcp_client *client;
990
991         assert_return(event, NULL);
992
993         client = new0(sd_dhcp_client, 1);
994         if (!client)
995                 return NULL;
996
997         client->event = sd_event_ref(event);
998         client->state = DHCP_STATE_INIT;
999         client->index = -1;
1000         client->fd = -1;
1001         client->attempt = 1;
1002
1003         client->req_opts_size = ELEMENTSOF(default_req_opts);
1004
1005         client->req_opts = memdup(default_req_opts, client->req_opts_size);
1006         if (!client->req_opts) {
1007                 free(client);
1008                 return NULL;
1009         }
1010
1011         return client;
1012 }