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