chiark / gitweb /
libsystemd-dhcp: Add functions for sending unicast UDP messages
[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 - 1];
386         }
387
388         while (sum >> 16)
389                 sum = (sum & 0xffff) + (sum >> 16);
390
391         return ~sum;
392 }
393
394 static void client_append_ip_headers(DHCPPacket *packet, uint16_t len)
395 {
396         packet->ip.version = IPVERSION;
397         packet->ip.ihl = DHCP_IP_SIZE / 4;
398         packet->ip.tot_len = htobe16(len);
399
400         packet->ip.protocol = IPPROTO_UDP;
401         packet->ip.saddr = INADDR_ANY;
402         packet->ip.daddr = INADDR_BROADCAST;
403
404         packet->udp.source = htobe16(DHCP_PORT_CLIENT);
405         packet->udp.dest = htobe16(DHCP_PORT_SERVER);
406         packet->udp.len = htobe16(len - DHCP_IP_SIZE);
407
408         packet->ip.check = packet->udp.len;
409         packet->udp.check = client_checksum(&packet->ip.ttl, len - 8);
410
411         packet->ip.ttl = IPDEFTTL;
412         packet->ip.check = 0;
413         packet->ip.check = client_checksum(&packet->ip, DHCP_IP_SIZE);
414 }
415
416 static int client_send_discover(sd_dhcp_client *client, uint16_t secs)
417 {
418         int err = 0;
419         _cleanup_free_ DHCPPacket *discover;
420         size_t optlen, len;
421         uint8_t *opt;
422
423         optlen = DHCP_CLIENT_MIN_OPTIONS_SIZE;
424         len = sizeof(DHCPPacket) + optlen;
425
426         discover = malloc0(len);
427
428         if (!discover)
429                 return -ENOMEM;
430
431         err = client_packet_init(client, DHCP_DISCOVER, &discover->dhcp,
432                                  secs, &opt, &optlen);
433         if (err < 0)
434                 return err;
435
436         if (client->last_addr != INADDR_ANY) {
437                 err = dhcp_option_append(&opt, &optlen,
438                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
439                                          4, &client->last_addr);
440                 if (err < 0)
441                         return err;
442         }
443
444         err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
445         if (err < 0)
446                 return err;
447
448         client_append_ip_headers(discover, len);
449
450         err = dhcp_network_send_raw_socket(client->fd, &client->link,
451                                            discover, len);
452
453         return err;
454 }
455
456 static int client_send_request(sd_dhcp_client *client, uint16_t secs)
457 {
458         _cleanup_free_ DHCPPacket *request;
459         size_t optlen, len;
460         int err;
461         uint8_t *opt;
462
463         optlen = DHCP_CLIENT_MIN_OPTIONS_SIZE;
464         len = DHCP_MESSAGE_SIZE + optlen;
465
466         request = malloc0(len);
467         if (!request)
468                 return -ENOMEM;
469
470         err = client_packet_init(client, DHCP_REQUEST, &request->dhcp, secs,
471                                  &opt, &optlen);
472         if (err < 0)
473                 return err;
474
475         if (client->state == DHCP_STATE_REQUESTING) {
476                 err = dhcp_option_append(&opt, &optlen,
477                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
478                                          4, &client->lease->address);
479                 if (err < 0)
480                         return err;
481
482                 err = dhcp_option_append(&opt, &optlen,
483                                          DHCP_OPTION_SERVER_IDENTIFIER,
484                                          4, &client->lease->server_address);
485                 if (err < 0)
486                         return err;
487         }
488
489         err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
490         if (err < 0)
491                 return err;
492
493         client_append_ip_headers(request, len);
494
495         err = dhcp_network_send_raw_socket(client->fd, &client->link,
496                                            request, len);
497
498         return err;
499 }
500
501 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
502                                  void *userdata)
503 {
504         sd_dhcp_client *client = userdata;
505         usec_t next_timeout;
506         uint16_t secs;
507         int err = 0;
508
509         secs = (usec - client->start_time) / USEC_PER_SEC;
510
511         if (client->attempt < 64)
512                 client->attempt *= 2;
513
514         next_timeout = usec + (client->attempt - 1) * USEC_PER_SEC +
515                 (random_u() & 0x1fffff);
516
517         err = sd_event_add_monotonic(client->event, next_timeout,
518                                      10 * USEC_PER_MSEC,
519                                      client_timeout_resend, client,
520                                      &client->timeout_resend);
521         if (err < 0)
522                 goto error;
523
524         switch (client->state) {
525         case DHCP_STATE_INIT:
526                 err = client_send_discover(client, secs);
527                 if (err >= 0) {
528                         client->state = DHCP_STATE_SELECTING;
529                         client->attempt = 1;
530                 } else {
531                         if (client->attempt >= 64)
532                                 goto error;
533                 }
534
535                 break;
536
537         case DHCP_STATE_SELECTING:
538                 err = client_send_discover(client, secs);
539                 if (err < 0 && client->attempt >= 64)
540                         goto error;
541
542                 break;
543
544         case DHCP_STATE_REQUESTING:
545                 err = client_send_request(client, secs);
546                 if (err < 0 && client->attempt >= 64)
547                          goto error;
548
549                 client->request_sent = usec;
550
551                 break;
552
553         case DHCP_STATE_INIT_REBOOT:
554         case DHCP_STATE_REBOOTING:
555         case DHCP_STATE_BOUND:
556         case DHCP_STATE_RENEWING:
557         case DHCP_STATE_REBINDING:
558
559                 break;
560         }
561
562         return 0;
563
564 error:
565         client_stop(client, err);
566
567         /* Errors were dealt with when stopping the client, don't spill
568            errors into the event loop handler */
569         return 0;
570 }
571
572 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
573                                  void *userdata)
574 {
575         sd_dhcp_client *client = userdata;
576
577         client_stop(client, DHCP_EVENT_EXPIRED);
578
579         return 0;
580 }
581
582 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
583 {
584         return 0;
585 }
586
587 static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
588 {
589         return 0;
590 }
591
592 static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
593                               void *user_data)
594 {
595         DHCPLease *lease = user_data;
596         be32_t val;
597
598         switch(code) {
599
600         case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
601                 if (len == 4) {
602                         memcpy(&val, option, 4);
603                         lease->lifetime = be32toh(val);
604                 }
605
606                 break;
607
608         case DHCP_OPTION_SERVER_IDENTIFIER:
609                 if (len >= 4)
610                         memcpy(&lease->server_address, option, 4);
611
612                 break;
613
614         case DHCP_OPTION_SUBNET_MASK:
615                 if (len >= 4)
616                         memcpy(&lease->subnet_mask, option, 4);
617
618                 break;
619
620         case DHCP_OPTION_ROUTER:
621                 if (len >= 4)
622                         memcpy(&lease->router, option, 4);
623
624                 break;
625
626         case DHCP_OPTION_RENEWAL_T1_TIME:
627                 if (len == 4) {
628                         memcpy(&val, option, 4);
629                         lease->t1 = be32toh(val);
630                 }
631
632                 break;
633
634         case DHCP_OPTION_REBINDING_T2_TIME:
635                 if (len == 4) {
636                         memcpy(&val, option, 4);
637                         lease->t2 = be32toh(val);
638                 }
639
640                 break;
641         }
642
643         return 0;
644 }
645
646 static int client_verify_headers(sd_dhcp_client *client, DHCPPacket *message,
647                                  size_t len)
648 {
649         size_t hdrlen;
650
651         if (len < (DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE))
652                 return -EINVAL;
653
654         hdrlen = message->ip.ihl * 4;
655         if (hdrlen < 20 || hdrlen > len || client_checksum(&message->ip,
656                                                            hdrlen))
657                 return -EINVAL;
658
659         message->ip.check = message->udp.len;
660         message->ip.ttl = 0;
661
662         if (hdrlen + be16toh(message->udp.len) > len ||
663             client_checksum(&message->ip.ttl, be16toh(message->udp.len) + 12))
664                 return -EINVAL;
665
666         if (be16toh(message->udp.source) != DHCP_PORT_SERVER ||
667             be16toh(message->udp.dest) != DHCP_PORT_CLIENT)
668                 return -EINVAL;
669
670         if (message->dhcp.op != BOOTREPLY)
671                 return -EINVAL;
672
673         if (be32toh(message->dhcp.xid) != client->xid)
674                 return -EINVAL;
675
676         if (memcmp(&message->dhcp.chaddr[0], &client->mac_addr.ether_addr_octet,
677                     ETHER_ADDR_LEN))
678                 return -EINVAL;
679
680         return 0;
681 }
682
683 static int client_receive_offer(sd_dhcp_client *client, DHCPPacket *offer,
684                                 size_t len)
685 {
686         int err;
687         DHCPLease *lease;
688
689         err = client_verify_headers(client, offer, len);
690         if (err < 0)
691                 return err;
692
693         lease = new0(DHCPLease, 1);
694         if (!lease)
695                 return -ENOMEM;
696
697         len = len - DHCP_IP_UDP_SIZE;
698         if (dhcp_option_parse(&offer->dhcp, len, client_parse_offer,
699                               lease) != DHCP_OFFER)
700                 goto error;
701
702         lease->address = offer->dhcp.yiaddr;
703
704         if (lease->address == INADDR_ANY ||
705             lease->server_address == INADDR_ANY ||
706             lease->subnet_mask == INADDR_ANY ||
707             lease->lifetime == 0)
708                 goto error;
709
710         client->lease = lease;
711
712         return 0;
713
714 error:
715         free(lease);
716
717         return -ENOMSG;
718 }
719
720 static int client_receive_ack(sd_dhcp_client *client, DHCPPacket *offer,
721                               size_t len)
722 {
723         int r;
724         DHCPLease *lease;
725
726         r = client_verify_headers(client, offer, len);
727         if (r < 0)
728                 return r;
729
730         lease = new0(DHCPLease, 1);
731         if (!lease)
732                 return -ENOMEM;
733
734         len = len - DHCP_IP_UDP_SIZE;
735         r = dhcp_option_parse(&offer->dhcp, len, client_parse_offer, lease);
736
737         if (r == DHCP_NAK) {
738                 r = DHCP_EVENT_NO_LEASE;
739                 goto error;
740         }
741
742         if (r != DHCP_ACK) {
743                 r = -ENOMSG;
744                 goto error;
745         }
746
747         lease->address = offer->dhcp.yiaddr;
748
749         if (lease->address == INADDR_ANY ||
750             lease->server_address == INADDR_ANY ||
751             lease->subnet_mask == INADDR_ANY || lease->lifetime == 0) {
752                 r = -ENOMSG;
753                 goto error;
754         }
755
756         r = DHCP_EVENT_IP_ACQUIRE;
757         if (client->lease) {
758                 if (client->lease->address != lease->address ||
759                     client->lease->subnet_mask != lease->subnet_mask ||
760                     client->lease->router != lease->router) {
761                         r = DHCP_EVENT_IP_CHANGE;
762                 }
763
764                 free(client->lease);
765         }
766
767         client->lease = lease;
768
769         return r;
770
771 error:
772         free(lease);
773
774         return r;
775 }
776
777 static uint64_t client_compute_timeout(uint64_t request_sent,
778                                        uint32_t lifetime)
779 {
780         return request_sent + (lifetime - 3) * USEC_PER_SEC +
781                 + (random_u() & 0x1fffff);
782 }
783
784 static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec)
785 {
786         int err;
787         uint64_t next_timeout;
788
789         if (client->lease->lifetime < 10)
790                 return -EINVAL;
791
792         if (!client->lease->t1)
793                 client->lease->t1 = client->lease->lifetime / 2;
794
795         next_timeout = client_compute_timeout(client->request_sent,
796                                               client->lease->t1);
797         if (next_timeout < usec)
798                 return -EINVAL;
799
800         err = sd_event_add_monotonic(client->event, next_timeout,
801                                      10 * USEC_PER_MSEC,
802                                      client_timeout_t1, client,
803                                      &client->timeout_t1);
804         if (err < 0)
805                 return err;
806
807         if (!client->lease->t2)
808                 client->lease->t2 = client->lease->lifetime * 7 / 8;
809
810         if (client->lease->t2 < client->lease->t1)
811                 return -EINVAL;
812
813         if (client->lease->lifetime < client->lease->t2)
814                 return -EINVAL;
815
816         next_timeout = client_compute_timeout(client->request_sent,
817                                               client->lease->t2);
818         if (next_timeout < usec)
819                 return -EINVAL;
820
821         err = sd_event_add_monotonic(client->event, next_timeout,
822                                      10 * USEC_PER_MSEC,
823                                      client_timeout_t2, client,
824                                      &client->timeout_t2);
825         if (err < 0)
826                 return err;
827
828         next_timeout = client_compute_timeout(client->request_sent,
829                                               client->lease->lifetime);
830         if (next_timeout < usec)
831                 return -EINVAL;
832
833         err = sd_event_add_monotonic(client->event, next_timeout,
834                                      10 * USEC_PER_MSEC,
835                                      client_timeout_expire, client,
836                                      &client->timeout_expire);
837         if (err < 0)
838                 return err;
839
840         return 0;
841 }
842
843 static int client_receive_raw_message(sd_event_source *s, int fd,
844                                       uint32_t revents, void *userdata)
845 {
846         sd_dhcp_client *client = userdata;
847         uint8_t buf[sizeof(DHCPPacket) + DHCP_CLIENT_MIN_OPTIONS_SIZE];
848         int buflen = sizeof(buf);
849         int len, r = 0;
850         DHCPPacket *message;
851         usec_t time_now;
852
853         len = read(fd, &buf, buflen);
854         if (len < 0)
855                 return 0;
856
857         r = sd_event_get_now_monotonic(client->event, &time_now);
858         if (r < 0)
859                 goto error;
860
861         message = (DHCPPacket *)&buf;
862
863         switch (client->state) {
864         case DHCP_STATE_SELECTING:
865
866                 if (client_receive_offer(client, message, len) >= 0) {
867
868                         client->timeout_resend =
869                                 sd_event_source_unref(client->timeout_resend);
870
871                         client->state = DHCP_STATE_REQUESTING;
872                         client->attempt = 1;
873
874                         r = sd_event_add_monotonic(client->event, time_now, 0,
875                                                    client_timeout_resend,
876                                                    client,
877                                                    &client->timeout_resend);
878                         if (r < 0)
879                                 goto error;
880                 }
881
882                 break;
883
884         case DHCP_STATE_REQUESTING:
885
886                 r = client_receive_ack(client, message, len);
887                 if (r == DHCP_EVENT_NO_LEASE)
888                         goto error;
889
890                 if (r >= 0) {
891                         client->timeout_resend =
892                                 sd_event_source_unref(client->timeout_resend);
893
894                         client->state = DHCP_STATE_BOUND;
895                         client->attempt = 1;
896
897                         client->last_addr = client->lease->address;
898
899                         r = client_set_lease_timeouts(client, time_now);
900                         if (r < 0 )
901                                 goto error;
902
903                         client_notify(client, DHCP_EVENT_IP_ACQUIRE);
904
905                         client->receive_message =
906                                 sd_event_source_unref(client->receive_message);
907                         close(client->fd);
908                         client->fd = -1;
909                 }
910
911                 r = 0;
912
913                 break;
914
915         case DHCP_STATE_INIT:
916         case DHCP_STATE_INIT_REBOOT:
917         case DHCP_STATE_REBOOTING:
918         case DHCP_STATE_BOUND:
919         case DHCP_STATE_RENEWING:
920         case DHCP_STATE_REBINDING:
921
922                 break;
923         }
924
925 error:
926         if (r < 0 || r == DHCP_EVENT_NO_LEASE)
927                 return client_stop(client, r);
928
929         return 0;
930 }
931
932 int sd_dhcp_client_start(sd_dhcp_client *client)
933 {
934         int err;
935
936         assert_return(client, -EINVAL);
937         assert_return(client->index >= 0, -EINVAL);
938         assert_return(client->state == DHCP_STATE_INIT ||
939                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
940
941         client->xid = random_u();
942
943         client->fd = dhcp_network_bind_raw_socket(client->index,
944                                                   &client->link);
945
946         if (client->fd < 0) {
947                 err = client->fd;
948                 goto error;
949         }
950
951         err = sd_event_add_io(client->event, client->fd, EPOLLIN,
952                               client_receive_raw_message, client,
953                               &client->receive_message);
954         if (err < 0)
955                 goto error;
956
957         client->start_time = now(CLOCK_MONOTONIC);
958         err = sd_event_add_monotonic(client->event, client->start_time, 0,
959                                      client_timeout_resend, client,
960                                      &client->timeout_resend);
961         if (err < 0)
962                 goto error;
963
964         return 0;
965
966 error:
967         client_stop(client, err);
968
969         return err;
970 }
971
972 int sd_dhcp_client_stop(sd_dhcp_client *client)
973 {
974         return client_stop(client, DHCP_EVENT_STOP);
975 }
976
977 sd_dhcp_client *sd_dhcp_client_free(sd_dhcp_client *client)
978 {
979         assert_return(client, NULL);
980
981         sd_dhcp_client_stop(client);
982
983         sd_event_unref(client->event);
984         free(client->req_opts);
985         free(client);
986
987         return NULL;
988 }
989
990 sd_dhcp_client *sd_dhcp_client_new(sd_event *event)
991 {
992         sd_dhcp_client *client;
993
994         assert_return(event, NULL);
995
996         client = new0(sd_dhcp_client, 1);
997         if (!client)
998                 return NULL;
999
1000         client->event = sd_event_ref(event);
1001         client->state = DHCP_STATE_INIT;
1002         client->index = -1;
1003         client->fd = -1;
1004         client->attempt = 1;
1005
1006         client->req_opts_size = ELEMENTSOF(default_req_opts);
1007
1008         client->req_opts = memdup(default_req_opts, client->req_opts_size);
1009         if (!client->req_opts) {
1010                 free(client);
1011                 return NULL;
1012         }
1013
1014         return client;
1015 }