chiark / gitweb /
1f676ccb655455ad1a15b21b70cb3a041fc1eb01
[elogind.git] / src / libsystemd-network / 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-internal.h"
33 #include "dhcp-lease-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         assert(secs);
210
211         r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt,
212                               optlen);
213         if (r < 0)
214                 return r;
215
216         /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
217            refuse to issue an DHCP lease if 'secs' is set to zero */
218         message->secs = htobe16(secs);
219
220         memcpy(&message->chaddr, &client->mac_addr, ETH_ALEN);
221
222         if (client->state == DHCP_STATE_RENEWING ||
223             client->state == DHCP_STATE_REBINDING)
224                 message->ciaddr = client->lease->address;
225
226         /* Some DHCP servers will refuse to issue an DHCP lease if the Client
227            Identifier option is not set */
228         r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
229                                ETH_ALEN, &client->mac_addr);
230         if (r < 0)
231                 return r;
232
233         if (type == DHCP_DISCOVER || type == DHCP_REQUEST) {
234                 be16_t max_size;
235
236                 r = dhcp_option_append(opt, optlen,
237                                        DHCP_OPTION_PARAMETER_REQUEST_LIST,
238                                        client->req_opts_size,
239                                        client->req_opts);
240                 if (r < 0)
241                         return r;
242
243                 /* Some DHCP servers will send bigger DHCP packets than the
244                    defined default size unless the Maximum Messge Size option
245                    is explicitely set */
246                 max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
247                                    DHCP_MIN_OPTIONS_SIZE);
248                 r = dhcp_option_append(opt, optlen,
249                                        DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
250                                        2, &max_size);
251                 if (r < 0)
252                         return r;
253         }
254
255         return 0;
256 }
257
258 static int client_send_discover(sd_dhcp_client *client, uint16_t secs) {
259         int err = 0;
260         _cleanup_free_ DHCPPacket *discover;
261         size_t optlen, len;
262         uint8_t *opt;
263
264         optlen = DHCP_MIN_OPTIONS_SIZE;
265         len = sizeof(DHCPPacket) + optlen;
266
267         discover = malloc0(len);
268
269         if (!discover)
270                 return -ENOMEM;
271
272         err = client_message_init(client, &discover->dhcp, DHCP_DISCOVER,
273                                   secs, &opt, &optlen);
274         if (err < 0)
275                 return err;
276
277         if (client->last_addr != INADDR_ANY) {
278                 err = dhcp_option_append(&opt, &optlen,
279                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
280                                          4, &client->last_addr);
281                 if (err < 0)
282                         return err;
283         }
284
285         err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
286         if (err < 0)
287                 return err;
288
289         dhcp_packet_append_ip_headers(discover, len);
290
291         err = dhcp_network_send_raw_socket(client->fd, &client->link,
292                                            discover, len);
293
294         log_dhcp_client(client, "DISCOVER");
295
296         return err;
297 }
298
299 static int client_send_request(sd_dhcp_client *client, uint16_t secs) {
300         _cleanup_free_ DHCPPacket *request;
301         size_t optlen, len;
302         int err;
303         uint8_t *opt;
304
305         optlen = DHCP_MIN_OPTIONS_SIZE;
306         len = sizeof(DHCPPacket) + optlen;
307
308         request = malloc0(len);
309         if (!request)
310                 return -ENOMEM;
311
312         err = client_message_init(client, &request->dhcp, DHCP_REQUEST, secs,
313                                   &opt, &optlen);
314         if (err < 0)
315                 return err;
316
317         if (client->state == DHCP_STATE_REQUESTING) {
318                 err = dhcp_option_append(&opt, &optlen,
319                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
320                                          4, &client->lease->address);
321                 if (err < 0)
322                         return err;
323
324                 err = dhcp_option_append(&opt, &optlen,
325                                          DHCP_OPTION_SERVER_IDENTIFIER,
326                                          4, &client->lease->server_address);
327                 if (err < 0)
328                         return err;
329         }
330
331         err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
332         if (err < 0)
333                 return err;
334
335         if (client->state == DHCP_STATE_RENEWING) {
336                 err = dhcp_network_send_udp_socket(client->fd,
337                                                    client->lease->server_address,
338                                                    DHCP_PORT_SERVER,
339                                                    &request->dhcp,
340                                                    len - DHCP_IP_UDP_SIZE);
341         } else {
342                 dhcp_packet_append_ip_headers(request, len);
343
344                 err = dhcp_network_send_raw_socket(client->fd, &client->link,
345                                                    request, len);
346         }
347
348         log_dhcp_client(client, "REQUEST");
349
350         return err;
351 }
352
353 static uint16_t client_update_secs(sd_dhcp_client *client, usec_t time_now)
354 {
355         client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
356
357         return client->secs;
358 }
359
360 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
361                                  void *userdata) {
362         sd_dhcp_client *client = userdata;
363         usec_t next_timeout = 0;
364         uint32_t time_left;
365         int r = 0;
366
367         assert(s);
368         assert(client);
369         assert(client->event);
370
371         switch (client->state) {
372         case DHCP_STATE_RENEWING:
373
374                 time_left = (client->lease->t2 - client->lease->t1) / 2;
375                 if (time_left < 60)
376                         time_left = 60;
377
378                 next_timeout = usec + time_left * USEC_PER_SEC;
379
380                 break;
381
382         case DHCP_STATE_REBINDING:
383
384                 time_left = (client->lease->lifetime - client->lease->t2) / 2;
385                 if (time_left < 60)
386                         time_left = 60;
387
388                 next_timeout = usec + time_left * USEC_PER_SEC;
389                 break;
390
391         case DHCP_STATE_INIT:
392         case DHCP_STATE_INIT_REBOOT:
393         case DHCP_STATE_REBOOTING:
394         case DHCP_STATE_SELECTING:
395         case DHCP_STATE_REQUESTING:
396         case DHCP_STATE_BOUND:
397
398                 if (client->attempt < 64)
399                         client->attempt *= 2;
400
401                 next_timeout = usec + (client->attempt - 1) * USEC_PER_SEC;
402
403                 break;
404         }
405
406         next_timeout += (random_u32() & 0x1fffff);
407
408         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
409
410         r = sd_event_add_monotonic(client->event,
411                                      &client->timeout_resend,
412                                      next_timeout,
413                                      10 * USEC_PER_MSEC,
414                                      client_timeout_resend, client);
415         if (r < 0)
416                 goto error;
417
418         r = sd_event_source_set_priority(client->timeout_resend,
419                                          client->event_priority);
420         if (r < 0)
421                 goto error;
422
423         switch (client->state) {
424         case DHCP_STATE_INIT:
425
426                 client_update_secs(client, usec);
427
428                 r = client_send_discover(client, client->secs);
429                 if (r >= 0) {
430                         client->state = DHCP_STATE_SELECTING;
431                         client->attempt = 1;
432                 } else {
433                         if (client->attempt >= 64)
434                                 goto error;
435                 }
436
437                 break;
438
439         case DHCP_STATE_SELECTING:
440                 client_update_secs(client, usec);
441
442                 r = client_send_discover(client, client->secs);
443                 if (r < 0 && client->attempt >= 64)
444                         goto error;
445
446                 break;
447
448         case DHCP_STATE_REQUESTING:
449         case DHCP_STATE_RENEWING:
450         case DHCP_STATE_REBINDING:
451                 r = client_send_request(client, client->secs);
452                 if (r < 0 && client->attempt >= 64)
453                          goto error;
454
455                 client->request_sent = usec;
456
457                 break;
458
459         case DHCP_STATE_INIT_REBOOT:
460         case DHCP_STATE_REBOOTING:
461         case DHCP_STATE_BOUND:
462
463                 break;
464         }
465
466         return 0;
467
468 error:
469         client_stop(client, r);
470
471         /* Errors were dealt with when stopping the client, don't spill
472            errors into the event loop handler */
473         return 0;
474 }
475
476 static int client_initialize_events(sd_dhcp_client *client,
477                                     sd_event_io_handler_t io_callback,
478                                     usec_t usec) {
479         int r;
480
481         assert(client);
482         assert(client->event);
483
484         r = sd_event_add_io(client->event, &client->receive_message,
485                             client->fd, EPOLLIN, io_callback,
486                             client);
487         if (r < 0)
488                 goto error;
489
490         r = sd_event_source_set_priority(client->receive_message,
491                                          client->event_priority);
492         if (r < 0)
493                 goto error;
494
495         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
496
497         r = sd_event_add_monotonic(client->event,
498                                    &client->timeout_resend,
499                                    usec, 0,
500                                    client_timeout_resend, client);
501         if (r < 0)
502                 goto error;
503
504         r = sd_event_source_set_priority(client->timeout_resend,
505                                          client->event_priority);
506
507 error:
508         if (r < 0)
509                 client_stop(client, r);
510
511         return 0;
512
513 }
514
515 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
516                                  void *userdata) {
517         sd_dhcp_client *client = userdata;
518
519         log_dhcp_client(client, "EXPIRED");
520
521         client_stop(client, DHCP_EVENT_EXPIRED);
522
523         return 0;
524 }
525
526 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
527         sd_dhcp_client *client = userdata;
528         int r;
529
530         if (client->fd >= 0) {
531                 client->receive_message =
532                         sd_event_source_unref(client->receive_message);
533                 close(client->fd);
534                 client->fd = -1;
535         }
536
537         client->state = DHCP_STATE_REBINDING;
538         client->attempt = 1;
539
540         r = dhcp_network_bind_raw_socket(client->index, &client->link);
541         if (r < 0) {
542                 client_stop(client, r);
543                 return 0;
544         }
545
546         client->fd = r;
547
548         log_dhcp_client(client, "TIMEOUT T2");
549
550         return client_initialize_events(client, client_receive_message_raw,
551                                         usec);
552 }
553
554 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
555                              void *userdata) {
556         sd_dhcp_client *client = userdata;
557         int r;
558
559         client->state = DHCP_STATE_RENEWING;
560         client->attempt = 1;
561
562         r = dhcp_network_bind_udp_socket(client->index,
563                                          client->lease->address,
564                                          DHCP_PORT_CLIENT);
565         if (r < 0) {
566                 client_stop(client, r);
567                 return 0;
568         }
569
570         client->fd = r;
571
572         log_dhcp_client(client, "TIMEOUT T1");
573
574         return client_initialize_events(client, client_receive_message_udp, usec);
575 }
576
577 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
578                                size_t len) {
579         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
580         int r;
581
582         r = dhcp_lease_new(&lease);
583         if (r < 0)
584                 return r;
585
586         r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
587         if (r != DHCP_OFFER)
588                 return -ENOMSG;
589
590         lease->address = offer->yiaddr;
591
592         if (lease->address == INADDR_ANY ||
593             lease->server_address == INADDR_ANY ||
594             lease->subnet_mask == INADDR_ANY ||
595             lease->lifetime == 0)
596                 return -ENOMSG;
597
598         client->lease = lease;
599         lease = NULL;
600
601         log_dhcp_client(client, "OFFER");
602
603         return 0;
604 }
605
606 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
607                              size_t len) {
608         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
609         int r;
610
611         r = dhcp_lease_new(&lease);
612         if (r < 0)
613                 return r;
614
615         r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
616         if (r == DHCP_NAK) {
617                 log_dhcp_client(client, "NAK");
618                 return DHCP_EVENT_NO_LEASE;
619         }
620
621         if (r != DHCP_ACK)
622                 return -ENOMSG;
623
624         lease->address = ack->yiaddr;
625
626         if (lease->address == INADDR_ANY ||
627             lease->server_address == INADDR_ANY ||
628             lease->subnet_mask == INADDR_ANY || lease->lifetime == 0)
629                 return -ENOMSG;
630
631         r = DHCP_EVENT_IP_ACQUIRE;
632         if (client->lease) {
633                 if (client->lease->address != lease->address ||
634                     client->lease->subnet_mask != lease->subnet_mask ||
635                     client->lease->router != lease->router) {
636                         r = DHCP_EVENT_IP_CHANGE;
637                 }
638
639                 client->lease = sd_dhcp_lease_unref(client->lease);
640         }
641
642         client->lease = lease;
643         lease = NULL;
644
645         log_dhcp_client(client, "ACK");
646
647         return r;
648 }
649
650 static uint64_t client_compute_timeout(uint64_t request_sent,
651                                        uint32_t lifetime) {
652         return request_sent + (lifetime - 3) * USEC_PER_SEC +
653                 + (random_u32() & 0x1fffff);
654 }
655
656 static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec) {
657         uint64_t next_timeout;
658         int r;
659
660         assert(client);
661         assert(client->event);
662
663         if (client->lease->lifetime < 10)
664                 return -EINVAL;
665
666         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
667         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
668         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
669
670         if (!client->lease->t1)
671                 client->lease->t1 = client->lease->lifetime / 2;
672
673         next_timeout = client_compute_timeout(client->request_sent,
674                                               client->lease->t1);
675         if (next_timeout < usec)
676                 return -EINVAL;
677
678         r = sd_event_add_monotonic(client->event,
679                                      &client->timeout_t1,
680                                      next_timeout,
681                                      10 * USEC_PER_MSEC,
682                                      client_timeout_t1, client);
683         if (r < 0)
684                 return r;
685
686         r = sd_event_source_set_priority(client->timeout_t1,
687                                          client->event_priority);
688         if (r < 0)
689                 return r;
690
691         if (!client->lease->t2)
692                 client->lease->t2 = client->lease->lifetime * 7 / 8;
693
694         if (client->lease->t2 < client->lease->t1)
695                 return -EINVAL;
696
697         if (client->lease->lifetime < client->lease->t2)
698                 return -EINVAL;
699
700         next_timeout = client_compute_timeout(client->request_sent,
701                                               client->lease->t2);
702         if (next_timeout < usec)
703                 return -EINVAL;
704
705         r = sd_event_add_monotonic(client->event,
706                                      &client->timeout_t2,
707                                      next_timeout,
708                                      10 * USEC_PER_MSEC,
709                                      client_timeout_t2, client);
710         if (r < 0)
711                 return r;
712
713         r = sd_event_source_set_priority(client->timeout_t2,
714                                          client->event_priority);
715         if (r < 0)
716                 return r;
717
718         next_timeout = client_compute_timeout(client->request_sent,
719                                               client->lease->lifetime);
720         if (next_timeout < usec)
721                 return -EINVAL;
722
723         r = sd_event_add_monotonic(client->event,
724                                      &client->timeout_expire, next_timeout,
725                                      10 * USEC_PER_MSEC,
726                                      client_timeout_expire, client);
727         if (r < 0)
728                 return r;
729
730         r = sd_event_source_set_priority(client->timeout_expire,
731                                          client->event_priority);
732         if (r < 0)
733                 return r;
734
735         return 0;
736 }
737
738 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
739                                  int len, usec_t time_now) {
740         int r = 0, notify_event = 0;
741
742         assert(client);
743         assert(client->event);
744         assert(message);
745
746         if (len < DHCP_MESSAGE_SIZE) {
747                 log_dhcp_client(client, "message too small (%d bytes): "
748                                 "ignoring", len);
749                 return 0;
750         }
751
752         if (message->op != BOOTREPLY) {
753                 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
754                 return 0;
755         }
756
757         if (be32toh(message->xid) != client->xid) {
758                 log_dhcp_client(client, "received xid (%u) does not match "
759                                 "expected (%u): ignoring",
760                                 be32toh(message->xid), client->xid);
761                 return 0;
762         }
763
764         if (memcmp(&message->chaddr[0], &client->mac_addr.ether_addr_octet,
765                    ETHER_ADDR_LEN)) {
766                 log_dhcp_client(client, "received chaddr does not match "
767                                 "expected: ignoring");
768                 return 0;
769         }
770
771         switch (client->state) {
772         case DHCP_STATE_SELECTING:
773
774                 r = client_handle_offer(client, message, len);
775                 if (r >= 0) {
776
777                         client->timeout_resend =
778                                 sd_event_source_unref(client->timeout_resend);
779
780                         client->state = DHCP_STATE_REQUESTING;
781                         client->attempt = 1;
782
783                         r = sd_event_add_monotonic(client->event,
784                                                    &client->timeout_resend,
785                                                    time_now, 0,
786                                                    client_timeout_resend,
787                                                    client);
788                         if (r < 0)
789                                 goto error;
790
791                         r = sd_event_source_set_priority(client->timeout_resend,
792                                                          client->event_priority);
793                         if (r < 0)
794                                 goto error;
795                 }
796
797                 break;
798
799         case DHCP_STATE_REQUESTING:
800         case DHCP_STATE_RENEWING:
801         case DHCP_STATE_REBINDING:
802
803                 r = client_handle_ack(client, message, len);
804
805                 if (r == DHCP_EVENT_NO_LEASE)
806                         goto error;
807
808                 if (r >= 0) {
809                         client->timeout_resend =
810                                 sd_event_source_unref(client->timeout_resend);
811
812                         if (client->state == DHCP_STATE_REQUESTING)
813                                 notify_event = DHCP_EVENT_IP_ACQUIRE;
814                         else if (r != DHCP_EVENT_IP_ACQUIRE)
815                                 notify_event = r;
816
817                         client->state = DHCP_STATE_BOUND;
818                         client->attempt = 1;
819
820                         client->last_addr = client->lease->address;
821
822                         r = client_set_lease_timeouts(client, time_now);
823                         if (r < 0)
824                                 goto error;
825
826                         if (notify_event)
827                                 client_notify(client, notify_event);
828
829                         client->receive_message =
830                                 sd_event_source_unref(client->receive_message);
831                         close(client->fd);
832                         client->fd = -1;
833                 }
834
835                 r = 0;
836
837                 break;
838
839         case DHCP_STATE_INIT:
840         case DHCP_STATE_INIT_REBOOT:
841         case DHCP_STATE_REBOOTING:
842         case DHCP_STATE_BOUND:
843
844                 break;
845         }
846
847 error:
848         if (r < 0 || r == DHCP_EVENT_NO_LEASE)
849                 return client_stop(client, r);
850
851         return 0;
852 }
853
854 static int client_receive_message_udp(sd_event_source *s, int fd,
855                                       uint32_t revents, void *userdata) {
856         sd_dhcp_client *client = userdata;
857         _cleanup_free_ DHCPMessage *message = NULL;
858         int buflen = 0, len, r;
859         usec_t time_now;
860
861         assert(s);
862         assert(client);
863         assert(client->event);
864
865         r = ioctl(fd, FIONREAD, &buflen);
866         if (r < 0 || buflen <= 0)
867                 buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE;
868
869         message = malloc0(buflen);
870         if (!message)
871                 return -ENOMEM;
872
873         len = read(fd, message, buflen);
874         if (len < 0)
875                 return 0;
876
877         r = sd_event_get_now_monotonic(client->event, &time_now);
878         if (r < 0)
879                 return client_stop(client, r);
880
881         return client_handle_message(client, message, len,
882                                      time_now);
883 }
884
885 static int client_receive_message_raw(sd_event_source *s, int fd,
886                                       uint32_t revents, void *userdata) {
887         sd_dhcp_client *client = userdata;
888         _cleanup_free_ DHCPPacket *packet = NULL;
889         usec_t time_now;
890         uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
891         struct iovec iov = {};
892         struct msghdr msg = {
893                 .msg_iov = &iov,
894                 .msg_iovlen = 1,
895                 .msg_control = cmsgbuf,
896                 .msg_controllen = sizeof(cmsgbuf),
897         };
898         struct cmsghdr *cmsg;
899         bool checksum = true;
900         int buflen = 0, len, r;
901
902         assert(s);
903         assert(client);
904         assert(client->event);
905
906         r = ioctl(fd, FIONREAD, &buflen);
907         if (r < 0 || buflen <= 0)
908                 buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE;
909
910         packet = malloc0(buflen);
911         if (!packet)
912                 return -ENOMEM;
913
914         iov.iov_base = packet;
915         iov.iov_len = buflen;
916
917         len = recvmsg(fd, &msg, 0);
918         if (len < 0) {
919                 log_dhcp_client(client, "could not receive message from raw "
920                                 "socket: %s", strerror(errno));
921                 return 0;
922         }
923
924         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
925                 if (cmsg->cmsg_level == SOL_PACKET && cmsg->cmsg_type == PACKET_AUXDATA) {
926                         struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
927
928                         checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
929                         break;
930                 }
931         }
932
933         r = dhcp_packet_verify_headers(packet, len, checksum);
934         if (r < 0)
935                 return 0;
936
937         len -= DHCP_IP_UDP_SIZE;
938
939         r = sd_event_get_now_monotonic(client->event, &time_now);
940         if (r < 0)
941                 return client_stop(client, r);
942
943         return client_handle_message(client, &packet->dhcp, len, time_now);
944 }
945
946 int sd_dhcp_client_start(sd_dhcp_client *client) {
947         int r;
948
949         assert_return(client, -EINVAL);
950         assert_return(client->event, -EINVAL);
951         assert_return(client->index > 0, -EINVAL);
952         assert_return(client->state == DHCP_STATE_INIT ||
953                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
954
955         client->xid = random_u32();
956
957         r = dhcp_network_bind_raw_socket(client->index, &client->link);
958
959         if (r < 0) {
960                 client_stop(client, r);
961                 return r;
962         }
963
964         client->fd = r;
965         client->start_time = now(CLOCK_MONOTONIC);
966         client->secs = 0;
967
968         log_dhcp_client(client, "STARTED");
969
970         return client_initialize_events(client, client_receive_message_raw,
971                                         client->start_time);
972 }
973
974 int sd_dhcp_client_stop(sd_dhcp_client *client) {
975         return client_stop(client, DHCP_EVENT_STOP);
976 }
977
978 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
979                                 int priority) {
980         int r;
981
982         assert_return(client, -EINVAL);
983         assert_return(!client->event, -EBUSY);
984
985         if (event)
986                 client->event = sd_event_ref(event);
987         else {
988                 r = sd_event_default(&client->event);
989                 if (r < 0)
990                         return 0;
991         }
992
993         client->event_priority = priority;
994
995         return 0;
996 }
997
998 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
999         assert_return(client, -EINVAL);
1000
1001         client->event = sd_event_unref(client->event);
1002
1003         return 0;
1004 }
1005
1006 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1007         if (!client)
1008                 return NULL;
1009
1010         return client->event;
1011 }
1012
1013 void sd_dhcp_client_free(sd_dhcp_client *client) {
1014         if (!client)
1015                 return;
1016
1017         sd_dhcp_client_stop(client);
1018         sd_dhcp_client_detach_event(client);
1019
1020         free(client->req_opts);
1021         free(client);
1022 }
1023
1024 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_free);
1025 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_freep)
1026
1027 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1028         _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1029
1030         assert_return(ret, -EINVAL);
1031
1032         client = new0(sd_dhcp_client, 1);
1033         if (!client)
1034                 return -ENOMEM;
1035
1036         client->state = DHCP_STATE_INIT;
1037         client->index = -1;
1038         client->fd = -1;
1039         client->attempt = 1;
1040
1041         client->req_opts_size = ELEMENTSOF(default_req_opts);
1042
1043         client->req_opts = memdup(default_req_opts, client->req_opts_size);
1044         if (!client->req_opts)
1045                 return -ENOMEM;
1046
1047         *ret = client;
1048         client = NULL;
1049
1050         return 0;
1051 }