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