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