chiark / gitweb /
dhcp: Add notification callback
[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         uint32_t address;
40         uint32_t server_address;
41         uint32_t subnet_mask;
42         uint32_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         uint32_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 -ENOBUFS;
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_ACK)
735                 goto error;
736
737         lease->address = offer->dhcp.yiaddr;
738
739         if (lease->address == INADDR_ANY ||
740             lease->server_address == INADDR_ANY ||
741             lease->subnet_mask == INADDR_ANY || lease->lifetime == 0) {
742                 r = -ENOMSG;
743                 goto error;
744         }
745
746         r = DHCP_EVENT_IP_ACQUIRE;
747         if (client->lease) {
748                 if (client->lease->address != lease->address ||
749                     client->lease->subnet_mask != lease->subnet_mask ||
750                     client->lease->router != lease->router) {
751                         r = DHCP_EVENT_IP_CHANGE;
752                 }
753
754                 free(client->lease);
755         }
756
757         client->lease = lease;
758
759         return r;
760
761 error:
762         free(lease);
763
764         return r;
765 }
766
767 static uint64_t client_compute_timeout(uint64_t request_sent,
768                                        uint32_t lifetime)
769 {
770         return request_sent + (lifetime - 3) * USEC_PER_SEC +
771                 + (random_u() & 0x1fffff);
772 }
773
774 static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec)
775 {
776         int err;
777         uint64_t next_timeout;
778
779         if (client->lease->lifetime < 10)
780                 return -EINVAL;
781
782         if (!client->lease->t1)
783                 client->lease->t1 = client->lease->lifetime / 2;
784
785         next_timeout = client_compute_timeout(client->request_sent,
786                                               client->lease->t1);
787         if (next_timeout < usec)
788                 return -EINVAL;
789
790         err = sd_event_add_monotonic(client->event, next_timeout,
791                                      10 * USEC_PER_MSEC,
792                                      client_timeout_t1, client,
793                                      &client->timeout_t1);
794         if (err < 0)
795                 return err;
796
797         if (!client->lease->t2)
798                 client->lease->t2 = client->lease->lifetime * 7 / 8;
799
800         if (client->lease->t2 < client->lease->t1)
801                 return -EINVAL;
802
803         if (client->lease->lifetime < client->lease->t2)
804                 return -EINVAL;
805
806         next_timeout = client_compute_timeout(client->request_sent,
807                                               client->lease->t2);
808         if (next_timeout < usec)
809                 return -EINVAL;
810
811         err = sd_event_add_monotonic(client->event, next_timeout,
812                                      10 * USEC_PER_MSEC,
813                                      client_timeout_t2, client,
814                                      &client->timeout_t2);
815         if (err < 0)
816                 return err;
817
818         next_timeout = client_compute_timeout(client->request_sent,
819                                               client->lease->lifetime);
820         if (next_timeout < usec)
821                 return -EINVAL;
822
823         err = sd_event_add_monotonic(client->event, next_timeout,
824                                      10 * USEC_PER_MSEC,
825                                      client_timeout_expire, client,
826                                      &client->timeout_expire);
827         if (err < 0)
828                 return err;
829
830         return 0;
831 }
832
833 static int client_receive_raw_message(sd_event_source *s, int fd,
834                                       uint32_t revents, void *userdata)
835 {
836         sd_dhcp_client *client = userdata;
837         uint8_t buf[sizeof(DHCPPacket) + DHCP_CLIENT_MIN_OPTIONS_SIZE];
838         int buflen = sizeof(buf);
839         int len, r = 0;
840         DHCPPacket *message;
841         usec_t time_now;
842
843         len = read(fd, &buf, buflen);
844         if (len < 0)
845                 return 0;
846
847         r = sd_event_get_now_monotonic(client->event, &time_now);
848         if (r < 0)
849                 goto error;
850
851         message = (DHCPPacket *)&buf;
852
853         switch (client->state) {
854         case DHCP_STATE_SELECTING:
855
856                 if (client_receive_offer(client, message, len) >= 0) {
857
858                         client->timeout_resend =
859                                 sd_event_source_unref(client->timeout_resend);
860
861                         client->state = DHCP_STATE_REQUESTING;
862                         client->attempt = 1;
863
864                         r = sd_event_add_monotonic(client->event, time_now, 0,
865                                                    client_timeout_resend,
866                                                    client,
867                                                    &client->timeout_resend);
868                         if (r < 0)
869                                 goto error;
870                 }
871
872                 break;
873
874         case DHCP_STATE_REQUESTING:
875
876                 r = client_receive_ack(client, message, len);
877                 if (r == DHCP_EVENT_NO_LEASE)
878                         goto error;
879
880                 if (r >= 0) {
881                         client->timeout_resend =
882                                 sd_event_source_unref(client->timeout_resend);
883
884                         client->state = DHCP_STATE_BOUND;
885                         client->attempt = 1;
886
887                         client->last_addr = client->lease->address;
888
889                         r = client_set_lease_timeouts(client, time_now);
890                         if (r < 0 )
891                                 goto error;
892
893                         client_notify(client, DHCP_EVENT_IP_ACQUIRE);
894
895                         close(client->fd);
896                         client->fd = -1;
897                         client->receive_message =
898                                 sd_event_source_unref(client->receive_message);
899                 }
900                 break;
901
902         case DHCP_STATE_INIT:
903         case DHCP_STATE_INIT_REBOOT:
904         case DHCP_STATE_REBOOTING:
905         case DHCP_STATE_BOUND:
906         case DHCP_STATE_RENEWING:
907         case DHCP_STATE_REBINDING:
908
909                 break;
910         }
911
912 error:
913         if (r < 0)
914                 return client_stop(client, r);
915
916         return 0;
917 }
918
919 int sd_dhcp_client_start(sd_dhcp_client *client)
920 {
921         int err;
922
923         assert_return(client, -EINVAL);
924         assert_return(client->index >= 0, -EINVAL);
925         assert_return(client->state == DHCP_STATE_INIT ||
926                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
927
928         client->xid = random_u();
929
930         client->fd = dhcp_network_bind_raw_socket(client->index,
931                                                   &client->link);
932
933         if (client->fd < 0) {
934                 err = client->fd;
935                 goto error;
936         }
937
938         err = sd_event_add_io(client->event, client->fd, EPOLLIN,
939                               client_receive_raw_message, client,
940                               &client->receive_message);
941         if (err < 0)
942                 goto error;
943
944         client->start_time = now(CLOCK_MONOTONIC);
945         err = sd_event_add_monotonic(client->event, client->start_time, 0,
946                                      client_timeout_resend, client,
947                                      &client->timeout_resend);
948         if (err < 0)
949                 goto error;
950
951         return 0;
952
953 error:
954         client_stop(client, err);
955
956         return err;
957 }
958
959 int sd_dhcp_client_stop(sd_dhcp_client *client)
960 {
961         return client_stop(client, DHCP_EVENT_STOP);
962 }
963
964 sd_dhcp_client *sd_dhcp_client_new(sd_event *event)
965 {
966         sd_dhcp_client *client;
967
968         assert_return(event, NULL);
969
970         client = new0(sd_dhcp_client, 1);
971         if (!client)
972                 return NULL;
973
974         client->event = sd_event_ref(event);
975         client->state = DHCP_STATE_INIT;
976         client->index = -1;
977         client->fd = -1;
978         client->attempt = 1;
979
980         client->req_opts_size = ELEMENTSOF(default_req_opts);
981
982         client->req_opts = memdup(default_req_opts, client->req_opts_size);
983         if (!client->req_opts) {
984                 free(client);
985                 return NULL;
986         }
987
988         return client;
989 }