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