chiark / gitweb /
sd-dhcp-client: log ifindex and mac address when starting
[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 <net/if_arp.h>
26 #include <netinet/ether.h>
27 #include <sys/param.h>
28 #include <sys/ioctl.h>
29
30 #include "util.h"
31 #include "list.h"
32 #include "refcnt.h"
33
34 #include "dhcp-protocol.h"
35 #include "dhcp-internal.h"
36 #include "dhcp-lease-internal.h"
37 #include "sd-dhcp-client.h"
38
39 struct sd_dhcp_client {
40         RefCount n_ref;
41
42         DHCPState state;
43         sd_event *event;
44         int event_priority;
45         sd_event_source *timeout_resend;
46         int index;
47         int fd;
48         union sockaddr_union link;
49         sd_event_source *receive_message;
50         uint8_t *req_opts;
51         size_t req_opts_allocated;
52         size_t req_opts_size;
53         be32_t last_addr;
54         struct {
55                 uint8_t type;
56                 struct ether_addr mac_addr;
57         } _packed_ client_id;
58         uint32_t xid;
59         usec_t start_time;
60         uint16_t secs;
61         unsigned int attempt;
62         usec_t request_sent;
63         sd_event_source *timeout_t1;
64         sd_event_source *timeout_t2;
65         sd_event_source *timeout_expire;
66         sd_dhcp_client_cb_t cb;
67         void *userdata;
68         sd_dhcp_lease *lease;
69 };
70
71 static const uint8_t default_req_opts[] = {
72         DHCP_OPTION_SUBNET_MASK,
73         DHCP_OPTION_ROUTER,
74         DHCP_OPTION_HOST_NAME,
75         DHCP_OPTION_DOMAIN_NAME,
76         DHCP_OPTION_DOMAIN_NAME_SERVER,
77         DHCP_OPTION_NTP_SERVER,
78 };
79
80 static int client_receive_message_raw(sd_event_source *s, int fd,
81                                       uint32_t revents, void *userdata);
82 static int client_receive_message_udp(sd_event_source *s, int fd,
83                                       uint32_t revents, void *userdata);
84 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error);
85
86 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
87                                 void *userdata) {
88         assert_return(client, -EINVAL);
89
90         client->cb = cb;
91         client->userdata = userdata;
92
93         return 0;
94 }
95
96 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
97         size_t i;
98
99         assert_return(client, -EINVAL);
100         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
101                               DHCP_STATE_STOPPED), -EBUSY);
102
103         switch(option) {
104         case DHCP_OPTION_PAD:
105         case DHCP_OPTION_OVERLOAD:
106         case DHCP_OPTION_MESSAGE_TYPE:
107         case DHCP_OPTION_PARAMETER_REQUEST_LIST:
108         case DHCP_OPTION_END:
109                 return -EINVAL;
110
111         default:
112                 break;
113         }
114
115         for (i = 0; i < client->req_opts_size; i++)
116                 if (client->req_opts[i] == option)
117                         return -EEXIST;
118
119         if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
120                             client->req_opts_size + 1))
121                 return -ENOMEM;
122
123         client->req_opts[client->req_opts_size++] = option;
124
125         return 0;
126 }
127
128 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
129                                        const struct in_addr *last_addr) {
130         assert_return(client, -EINVAL);
131         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
132                               DHCP_STATE_STOPPED), -EBUSY);
133
134         if (last_addr)
135                 client->last_addr = last_addr->s_addr;
136         else
137                 client->last_addr = INADDR_ANY;
138
139         return 0;
140 }
141
142 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
143         assert_return(client, -EINVAL);
144         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
145                               DHCP_STATE_STOPPED), -EBUSY);
146         assert_return(interface_index >= -1, -EINVAL);
147
148         client->index = interface_index;
149
150         return 0;
151 }
152
153 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
154                            const struct ether_addr *addr) {
155         bool need_restart = false;
156
157         assert_return(client, -EINVAL);
158         assert_return(addr, -EINVAL);
159
160         if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
161                 return 0;
162
163         if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
164                 log_dhcp_client(client, "Changing MAC address on running DHCP "
165                                 "client, restarting");
166                 need_restart = true;
167                 client = client_stop(client, DHCP_EVENT_STOP);
168         }
169
170         if (!client)
171                 return 0;
172
173         memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
174         client->client_id.type = 0x01;
175
176         if (need_restart && client->state != DHCP_STATE_STOPPED)
177                 sd_dhcp_client_start(client);
178
179         return 0;
180 }
181
182 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
183         assert_return(client, -EINVAL);
184         assert_return(ret, -EINVAL);
185
186         if (client->state != DHCP_STATE_BOUND &&
187             client->state != DHCP_STATE_RENEWING &&
188             client->state != DHCP_STATE_REBINDING)
189                 return -EADDRNOTAVAIL;
190
191         *ret = sd_dhcp_lease_ref(client->lease);
192
193         return 0;
194 }
195
196 static sd_dhcp_client *client_notify(sd_dhcp_client *client, int event) {
197         if (client->cb) {
198                 client = sd_dhcp_client_ref(client);
199                 client->cb(client, event, client->userdata);
200                 client = sd_dhcp_client_unref(client);
201         }
202
203         return client;
204 }
205
206 static int client_initialize(sd_dhcp_client *client) {
207         assert_return(client, -EINVAL);
208
209         client->receive_message =
210                 sd_event_source_unref(client->receive_message);
211
212         client->fd = safe_close(client->fd);
213
214         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
215
216         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
217         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
218         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
219
220         client->attempt = 1;
221
222         client->state = DHCP_STATE_INIT;
223         client->xid = 0;
224
225         if (client->lease)
226                 client->lease = sd_dhcp_lease_unref(client->lease);
227
228         return 0;
229 }
230
231 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error) {
232         assert_return(client, NULL);
233
234         log_dhcp_client(client, "STOPPED: %s", strerror(-error));
235
236         client = client_notify(client, error);
237
238         if (client)
239                 client_initialize(client);
240
241         return client;
242 }
243
244 static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
245                                uint8_t type, uint8_t **opt, size_t *optlen) {
246         be16_t max_size;
247         int r;
248
249         assert(client);
250         assert(client->secs);
251         assert(message);
252         assert(opt);
253         assert(optlen);
254         assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
255
256         r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt,
257                               optlen);
258         if (r < 0)
259                 return r;
260
261         /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
262            refuse to issue an DHCP lease if 'secs' is set to zero */
263         message->secs = htobe16(client->secs);
264
265         /* RFC2132 section 4.1.1:
266            The client MUST include its hardware address in the ’chaddr’ field, if
267            necessary for delivery of DHCP reply messages.
268          */
269         memcpy(&message->chaddr, &client->client_id.mac_addr, ETH_ALEN);
270
271         /* Some DHCP servers will refuse to issue an DHCP lease if the Client
272            Identifier option is not set */
273         r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
274                                sizeof(client->client_id), &client->client_id);
275         if (r < 0)
276                 return r;
277
278
279         /* RFC2131 section 3.5:
280            in its initial DHCPDISCOVER or DHCPREQUEST message, a
281            client may provide the server with a list of specific
282            parameters the client is interested in. If the client
283            includes a list of parameters in a DHCPDISCOVER message,
284            it MUST include that list in any subsequent DHCPREQUEST
285            messages.
286          */
287         r = dhcp_option_append(opt, optlen,
288                                DHCP_OPTION_PARAMETER_REQUEST_LIST,
289                                client->req_opts_size,
290                                client->req_opts);
291         if (r < 0)
292                 return r;
293
294         /* RFC2131 section 3.5:
295            The client SHOULD include the ’maximum DHCP message size’ option to
296            let the server know how large the server may make its DHCP messages.
297
298            Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
299            than the defined default size unless the Maximum Messge Size option
300            is explicitely set
301          */
302         max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
303                            DHCP_MIN_OPTIONS_SIZE);
304         r = dhcp_option_append(opt, optlen,
305                                DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
306                                2, &max_size);
307         if (r < 0)
308                 return r;
309
310         return 0;
311 }
312
313 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
314                                 size_t len) {
315         dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
316                                       INADDR_BROADCAST, DHCP_PORT_SERVER, len);
317
318         return dhcp_network_send_raw_socket(client->fd, &client->link,
319                                             packet, len);
320 }
321
322 static int client_send_discover(sd_dhcp_client *client) {
323         _cleanup_free_ DHCPPacket *discover = NULL;
324         size_t optlen, len;
325         uint8_t *opt;
326         usec_t time_now;
327         int r;
328
329         assert(client);
330         assert(client->state == DHCP_STATE_INIT ||
331                client->state == DHCP_STATE_SELECTING);
332
333         /* See RFC2131 section 4.4.1 */
334
335         r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
336         if (r < 0)
337                 return r;
338         assert(time_now >= client->start_time);
339
340         /* seconds between sending first and last DISCOVER
341          * must always be strictly positive to deal with broken servers */
342         client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
343
344         optlen = DHCP_MIN_OPTIONS_SIZE;
345         len = sizeof(DHCPPacket) + optlen;
346
347         discover = malloc0(len);
348         if (!discover)
349                 return -ENOMEM;
350
351         r = client_message_init(client, &discover->dhcp, DHCP_DISCOVER,
352                                 &opt, &optlen);
353         if (r < 0)
354                 return r;
355
356         /* the client may suggest values for the network address
357            and lease time in the DHCPDISCOVER message. The client may include
358            the ’requested IP address’ option to suggest that a particular IP
359            address be assigned, and may include the ’IP address lease time’
360            option to suggest the lease time it would like.
361          */
362         if (client->last_addr != INADDR_ANY) {
363                 r = dhcp_option_append(&opt, &optlen,
364                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
365                                          4, &client->last_addr);
366                 if (r < 0)
367                         return r;
368         }
369
370         r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
371         if (r < 0)
372                 return r;
373
374         /* We currently ignore:
375            The client SHOULD wait a random time between one and ten seconds to
376            desynchronize the use of DHCP at startup.
377          */
378         r = dhcp_client_send_raw(client, discover, len - optlen);
379         if (r < 0)
380                 return r;
381
382         log_dhcp_client(client, "DISCOVER");
383
384         return 0;
385 }
386
387 static int client_send_request(sd_dhcp_client *client) {
388         _cleanup_free_ DHCPPacket *request;
389         size_t optlen, len;
390         uint8_t *opt;
391         int r;
392
393         optlen = DHCP_MIN_OPTIONS_SIZE;
394         len = sizeof(DHCPPacket) + optlen;
395
396         request = malloc0(len);
397         if (!request)
398                 return -ENOMEM;
399
400         r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt,
401                                 &optlen);
402         if (r < 0)
403                 return r;
404
405         switch (client->state) {
406         /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
407            SELECTING should be REQUESTING)
408          */
409
410         case DHCP_STATE_REQUESTING:
411                 /* Client inserts the address of the selected server in ’server
412                    identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
413                    filled in with the yiaddr value from the chosen DHCPOFFER.
414                  */
415
416                 r = dhcp_option_append(&opt, &optlen,
417                                        DHCP_OPTION_SERVER_IDENTIFIER,
418                                        4, &client->lease->server_address);
419                 if (r < 0)
420                         return r;
421
422                 r = dhcp_option_append(&opt, &optlen,
423                                        DHCP_OPTION_REQUESTED_IP_ADDRESS,
424                                        4, &client->lease->address);
425                 if (r < 0)
426                         return r;
427
428                 break;
429
430         case DHCP_STATE_INIT_REBOOT:
431                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
432                    option MUST be filled in with client’s notion of its previously
433                    assigned address. ’ciaddr’ MUST be zero.
434                  */
435                 r = dhcp_option_append(&opt, &optlen,
436                                        DHCP_OPTION_REQUESTED_IP_ADDRESS,
437                                        4, &client->last_addr);
438                 if (r < 0)
439                         return r;
440                 break;
441
442         case DHCP_STATE_RENEWING:
443                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
444                    option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
445                    client’s IP address.
446                 */
447
448                 /* fall through */
449         case DHCP_STATE_REBINDING:
450                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
451                    option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
452                    client’s IP address.
453
454                    This message MUST be broadcast to the 0xffffffff IP broadcast address.
455                  */
456                 request->dhcp.ciaddr = client->lease->address;
457
458                 break;
459
460         case DHCP_STATE_INIT:
461         case DHCP_STATE_SELECTING:
462         case DHCP_STATE_REBOOTING:
463         case DHCP_STATE_BOUND:
464         case DHCP_STATE_STOPPED:
465                 return -EINVAL;
466         }
467
468         r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
469         if (r < 0)
470                 return r;
471
472         if (client->state == DHCP_STATE_RENEWING) {
473                 r = dhcp_network_send_udp_socket(client->fd,
474                                                  client->lease->server_address,
475                                                  DHCP_PORT_SERVER,
476                                                  &request->dhcp,
477                                                  len - optlen - DHCP_IP_UDP_SIZE);
478         } else {
479                 r = dhcp_client_send_raw(client, request, len - optlen);
480         }
481         if (r < 0)
482                 return r;
483
484         switch (client->state) {
485         case DHCP_STATE_REQUESTING:
486                 log_dhcp_client(client, "REQUEST (requesting)");
487                 break;
488         case DHCP_STATE_INIT_REBOOT:
489                 log_dhcp_client(client, "REQUEST (init-reboot)");
490                 break;
491         case DHCP_STATE_RENEWING:
492                 log_dhcp_client(client, "REQUEST (renewing)");
493                 break;
494         case DHCP_STATE_REBINDING:
495                 log_dhcp_client(client, "REQUEST (rebinding)");
496                 break;
497         default:
498                 log_dhcp_client(client, "REQUEST (invalid)");
499                 break;
500         }
501
502         return 0;
503 }
504
505 static int client_start(sd_dhcp_client *client);
506
507 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
508                                  void *userdata) {
509         sd_dhcp_client *client = userdata;
510         usec_t next_timeout = 0;
511         uint64_t time_now;
512         uint32_t time_left;
513         int r;
514
515         assert(s);
516         assert(client);
517         assert(client->event);
518
519         r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
520         if (r < 0)
521                 goto error;
522
523         switch (client->state) {
524         case DHCP_STATE_RENEWING:
525
526                 time_left = (client->lease->t2 - client->lease->t1) / 2;
527                 if (time_left < 60)
528                         time_left = 60;
529
530                 next_timeout = time_now + time_left * USEC_PER_SEC;
531
532                 break;
533
534         case DHCP_STATE_REBINDING:
535
536                 time_left = (client->lease->lifetime - client->lease->t2) / 2;
537                 if (time_left < 60)
538                         time_left = 60;
539
540                 next_timeout = time_now + time_left * USEC_PER_SEC;
541                 break;
542
543         case DHCP_STATE_REBOOTING:
544                 /* start over as we did not receive a timely ack or nak */
545                 r = client_initialize(client);
546                 if (r < 0)
547                         goto error;
548
549                 r = client_start(client);
550                 if (r < 0)
551                         goto error;
552                 else {
553                         log_dhcp_client(client, "REBOOTED");
554                         return 0;
555                 }
556
557         case DHCP_STATE_INIT:
558         case DHCP_STATE_INIT_REBOOT:
559         case DHCP_STATE_SELECTING:
560         case DHCP_STATE_REQUESTING:
561         case DHCP_STATE_BOUND:
562
563                 if (client->attempt < 64)
564                         client->attempt *= 2;
565
566                 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
567
568                 break;
569
570         case DHCP_STATE_STOPPED:
571                 r = -EINVAL;
572                 goto error;
573         }
574
575         next_timeout += (random_u32() & 0x1fffff);
576
577         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
578
579         r = sd_event_add_time(client->event,
580                               &client->timeout_resend,
581                               CLOCK_MONOTONIC,
582                               next_timeout, 10 * USEC_PER_MSEC,
583                               client_timeout_resend, client);
584         if (r < 0)
585                 goto error;
586
587         r = sd_event_source_set_priority(client->timeout_resend,
588                                          client->event_priority);
589         if (r < 0)
590                 goto error;
591
592         switch (client->state) {
593         case DHCP_STATE_INIT:
594                 r = client_send_discover(client);
595                 if (r >= 0) {
596                         client->state = DHCP_STATE_SELECTING;
597                         client->attempt = 1;
598                 } else {
599                         if (client->attempt >= 64)
600                                 goto error;
601                 }
602
603                 break;
604
605         case DHCP_STATE_SELECTING:
606                 r = client_send_discover(client);
607                 if (r < 0 && client->attempt >= 64)
608                         goto error;
609
610                 break;
611
612         case DHCP_STATE_INIT_REBOOT:
613         case DHCP_STATE_REQUESTING:
614         case DHCP_STATE_RENEWING:
615         case DHCP_STATE_REBINDING:
616                 r = client_send_request(client);
617                 if (r < 0 && client->attempt >= 64)
618                          goto error;
619
620                 if (client->state == DHCP_STATE_INIT_REBOOT)
621                         client->state = DHCP_STATE_REBOOTING;
622
623                 client->request_sent = time_now;
624
625                 break;
626
627         case DHCP_STATE_REBOOTING:
628         case DHCP_STATE_BOUND:
629
630                 break;
631
632         case DHCP_STATE_STOPPED:
633                 r = -EINVAL;
634                 goto error;
635         }
636
637         return 0;
638
639 error:
640         client_stop(client, r);
641
642         /* Errors were dealt with when stopping the client, don't spill
643            errors into the event loop handler */
644         return 0;
645 }
646
647 static int client_initialize_events(sd_dhcp_client *client,
648                                     sd_event_io_handler_t io_callback) {
649         int r;
650
651         assert(client);
652         assert(client->event);
653
654         r = sd_event_add_io(client->event, &client->receive_message,
655                             client->fd, EPOLLIN, io_callback,
656                             client);
657         if (r < 0)
658                 goto error;
659
660         r = sd_event_source_set_priority(client->receive_message,
661                                          client->event_priority);
662         if (r < 0)
663                 goto error;
664
665         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
666
667         r = sd_event_add_time(client->event,
668                               &client->timeout_resend,
669                               CLOCK_MONOTONIC,
670                               0, 0,
671                               client_timeout_resend, client);
672         if (r < 0)
673                 goto error;
674
675         r = sd_event_source_set_priority(client->timeout_resend,
676                                          client->event_priority);
677
678 error:
679         if (r < 0)
680                 client_stop(client, r);
681
682         return 0;
683
684 }
685
686 static int client_start(sd_dhcp_client *client) {
687         int r;
688
689         assert_return(client, -EINVAL);
690         assert_return(client->event, -EINVAL);
691         assert_return(client->index > 0, -EINVAL);
692         assert_return(client->fd < 0, -EBUSY);
693         assert_return(client->xid == 0, -EINVAL);
694         assert_return(client->state == DHCP_STATE_INIT ||
695                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
696
697         client->xid = random_u32();
698
699         r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
700         if (r < 0) {
701                 client_stop(client, r);
702                 return r;
703         }
704         client->fd = r;
705
706         if (client->state == DHCP_STATE_INIT) {
707                 client->start_time = now(CLOCK_MONOTONIC);
708                 client->secs = 0;
709         }
710
711         return client_initialize_events(client, client_receive_message_raw);
712 }
713
714 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
715                                  void *userdata) {
716         sd_dhcp_client *client = userdata;
717
718         log_dhcp_client(client, "EXPIRED");
719
720         client = client_notify(client, DHCP_EVENT_EXPIRED);
721
722         /* lease was lost, start over if not freed or stopped in callback */
723         if (client && client->state != DHCP_STATE_STOPPED) {
724                 client_initialize(client);
725                 client_start(client);
726         }
727
728         return 0;
729 }
730
731 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
732         sd_dhcp_client *client = userdata;
733         int r;
734
735         client->receive_message = sd_event_source_unref(client->receive_message);
736         client->fd = safe_close(client->fd);
737
738         client->state = DHCP_STATE_REBINDING;
739         client->attempt = 1;
740
741         r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
742         if (r < 0) {
743                 client_stop(client, r);
744                 return 0;
745         }
746         client->fd = r;
747
748         return client_initialize_events(client, client_receive_message_raw);
749 }
750
751 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
752                              void *userdata) {
753         sd_dhcp_client *client = userdata;
754         int r;
755
756         client->state = DHCP_STATE_RENEWING;
757         client->attempt = 1;
758
759         r = dhcp_network_bind_udp_socket(client->index,
760                                          client->lease->address,
761                                          DHCP_PORT_CLIENT);
762         if (r < 0) {
763                 client_stop(client, r);
764                 return 0;
765         }
766
767         client->fd = r;
768
769         return client_initialize_events(client, client_receive_message_udp);
770 }
771
772 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
773                                size_t len) {
774         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
775         int r;
776
777         r = dhcp_lease_new(&lease);
778         if (r < 0)
779                 return r;
780
781         r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
782         if (r != DHCP_OFFER) {
783                 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
784                 return -ENOMSG;
785         }
786
787         lease->next_server = offer->siaddr;
788
789         lease->address = offer->yiaddr;
790
791         if (lease->address == INADDR_ANY ||
792             lease->server_address == INADDR_ANY ||
793             lease->lifetime == 0) {
794                 log_dhcp_client(client, "receieved lease lacks address, server "
795                                 "address or lease lifetime, ignoring");
796                 return -ENOMSG;
797         }
798
799         if (lease->subnet_mask == INADDR_ANY) {
800                 r = dhcp_lease_set_default_subnet_mask(lease);
801                 if (r < 0) {
802                         log_dhcp_client(client, "receieved lease lacks subnet "
803                                         "mask, and a fallback one can not be "
804                                         "generated, ignoring");
805                         return -ENOMSG;
806                 }
807         }
808
809         sd_dhcp_lease_unref(client->lease);
810         client->lease = lease;
811         lease = NULL;
812
813         log_dhcp_client(client, "OFFER");
814
815         return 0;
816 }
817
818 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
819                              size_t len) {
820         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
821         int r;
822
823         r = dhcp_lease_new(&lease);
824         if (r < 0)
825                 return r;
826
827         r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
828         if (r == DHCP_NAK) {
829                 log_dhcp_client(client, "NAK");
830                 return DHCP_EVENT_NO_LEASE;
831         }
832
833         if (r != DHCP_ACK) {
834                 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
835                 return -ENOMSG;
836         }
837
838         lease->next_server = ack->siaddr;
839
840         lease->address = ack->yiaddr;
841
842         if (lease->address == INADDR_ANY ||
843             lease->server_address == INADDR_ANY ||
844             lease->lifetime == 0) {
845                 log_dhcp_client(client, "receieved lease lacks address, server "
846                                 "address or lease lifetime, ignoring");
847                 return -ENOMSG;
848         }
849
850         if (lease->subnet_mask == INADDR_ANY) {
851                 r = dhcp_lease_set_default_subnet_mask(lease);
852                 if (r < 0) {
853                         log_dhcp_client(client, "receieved lease lacks subnet "
854                                         "mask, and a fallback one can not be "
855                                         "generated, ignoring");
856                         return -ENOMSG;
857                 }
858         }
859
860         r = DHCP_EVENT_IP_ACQUIRE;
861         if (client->lease) {
862                 if (client->lease->address != lease->address ||
863                     client->lease->subnet_mask != lease->subnet_mask ||
864                     client->lease->router != lease->router) {
865                         r = DHCP_EVENT_IP_CHANGE;
866                 }
867
868                 client->lease = sd_dhcp_lease_unref(client->lease);
869         }
870
871         client->lease = lease;
872         lease = NULL;
873
874         log_dhcp_client(client, "ACK");
875
876         return r;
877 }
878
879 static uint64_t client_compute_timeout(sd_dhcp_client *client,
880                                        uint32_t lifetime, double factor) {
881         assert(client);
882         assert(client->request_sent);
883         assert(lifetime);
884
885         return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
886                 + (random_u32() & 0x1fffff);
887 }
888
889 static int client_set_lease_timeouts(sd_dhcp_client *client) {
890         usec_t time_now;
891         uint64_t lifetime_timeout;
892         uint64_t t2_timeout;
893         uint64_t t1_timeout;
894         char time_string[FORMAT_TIMESPAN_MAX];
895         int r;
896
897         assert(client);
898         assert(client->event);
899         assert(client->lease);
900         assert(client->lease->lifetime);
901
902         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
903         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
904         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
905
906         /* don't set timers for infinite leases */
907         if (client->lease->lifetime == 0xffffffff)
908                 return 0;
909
910         r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
911         if (r < 0)
912                 return r;
913         assert(client->request_sent <= time_now);
914
915         /* convert the various timeouts from relative (secs) to absolute (usecs) */
916         lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
917         if (client->lease->t1 && client->lease->t2) {
918                 /* both T1 and T2 are given */
919                 if (client->lease->t1 < client->lease->t2 &&
920                     client->lease->t2 < client->lease->lifetime) {
921                         /* they are both valid */
922                         t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
923                         t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
924                 } else {
925                         /* discard both */
926                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
927                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
928                         t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
929                         client->lease->t1 = client->lease->lifetime / 2;
930                 }
931         } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
932                 /* only T2 is given, and it is valid */
933                 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
934                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
935                 client->lease->t1 = client->lease->lifetime / 2;
936                 if (t2_timeout <= t1_timeout) {
937                         /* the computed T1 would be invalid, so discard T2 */
938                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
939                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
940                 }
941         } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
942                 /* only T1 is given, and it is valid */
943                 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
944                 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
945                 client->lease->t2 = (client->lease->lifetime * 7) / 8;
946                 if (t2_timeout <= t1_timeout) {
947                         /* the computed T2 would be invalid, so discard T1 */
948                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
949                         client->lease->t2 = client->lease->lifetime / 2;
950                 }
951         } else {
952                 /* fall back to the default timeouts */
953                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
954                 client->lease->t1 = client->lease->lifetime / 2;
955                 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
956                 client->lease->t2 = (client->lease->lifetime * 7) / 8;
957         }
958
959         /* arm lifetime timeout */
960         r = sd_event_add_time(client->event, &client->timeout_expire,
961                               CLOCK_MONOTONIC,
962                               lifetime_timeout, 10 * USEC_PER_MSEC,
963                               client_timeout_expire, client);
964         if (r < 0)
965                 return r;
966
967         r = sd_event_source_set_priority(client->timeout_expire,
968                                          client->event_priority);
969         if (r < 0)
970                 return r;
971
972         log_dhcp_client(client, "lease expires in %s",
973                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
974                         lifetime_timeout - time_now, 0));
975
976         /* don't arm earlier timeouts if this has already expired */
977         if (lifetime_timeout <= time_now)
978                 return 0;
979
980         /* arm T2 timeout */
981         r = sd_event_add_time(client->event,
982                               &client->timeout_t2,
983                               CLOCK_MONOTONIC,
984                               t2_timeout,
985                               10 * USEC_PER_MSEC,
986                               client_timeout_t2, client);
987         if (r < 0)
988                 return r;
989
990         r = sd_event_source_set_priority(client->timeout_t2,
991                                          client->event_priority);
992         if (r < 0)
993                 return r;
994
995         log_dhcp_client(client, "T2 expires in %s",
996                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
997                         t2_timeout - time_now, 0));
998
999         /* don't arm earlier timeout if this has already expired */
1000         if (t2_timeout <= time_now)
1001                 return 0;
1002
1003         /* arm T1 timeout */
1004         r = sd_event_add_time(client->event,
1005                               &client->timeout_t1,
1006                               CLOCK_MONOTONIC,
1007                               t1_timeout, 10 * USEC_PER_MSEC,
1008                               client_timeout_t1, client);
1009         if (r < 0)
1010                 return r;
1011
1012         r = sd_event_source_set_priority(client->timeout_t1,
1013                                          client->event_priority);
1014         if (r < 0)
1015                 return r;
1016
1017         log_dhcp_client(client, "T1 expires in %s",
1018                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1019                         t1_timeout - time_now, 0));
1020
1021         return 0;
1022 }
1023
1024 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1025                                  int len) {
1026         int r = 0, notify_event = 0;
1027
1028         assert(client);
1029         assert(client->event);
1030         assert(message);
1031
1032         if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1033                 log_dhcp_client(client, "not a DHCP message: ignoring");
1034                 return 0;
1035         }
1036
1037         if (message->op != BOOTREPLY) {
1038                 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1039                 return 0;
1040         }
1041
1042         if (be32toh(message->xid) != client->xid) {
1043                 log_dhcp_client(client, "received xid (%u) does not match "
1044                                 "expected (%u): ignoring",
1045                                 be32toh(message->xid), client->xid);
1046                 return 0;
1047         }
1048
1049         if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
1050                 log_dhcp_client(client, "not an ethernet packet");
1051                 return 0;
1052         }
1053
1054         if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
1055                    ETH_ALEN)) {
1056                 log_dhcp_client(client, "received chaddr does not match "
1057                                 "expected: ignoring");
1058                 return 0;
1059         }
1060
1061         switch (client->state) {
1062         case DHCP_STATE_SELECTING:
1063
1064                 r = client_handle_offer(client, message, len);
1065                 if (r >= 0) {
1066
1067                         client->timeout_resend =
1068                                 sd_event_source_unref(client->timeout_resend);
1069
1070                         client->state = DHCP_STATE_REQUESTING;
1071                         client->attempt = 1;
1072
1073                         r = sd_event_add_time(client->event,
1074                                               &client->timeout_resend,
1075                                               CLOCK_MONOTONIC,
1076                                               0, 0,
1077                                               client_timeout_resend, client);
1078                         if (r < 0)
1079                                 goto error;
1080
1081                         r = sd_event_source_set_priority(client->timeout_resend,
1082                                                          client->event_priority);
1083                         if (r < 0)
1084                                 goto error;
1085                 } else if (r == -ENOMSG)
1086                         /* invalid message, let's ignore it */
1087                         return 0;
1088
1089                 break;
1090
1091         case DHCP_STATE_REBOOTING:
1092         case DHCP_STATE_REQUESTING:
1093         case DHCP_STATE_RENEWING:
1094         case DHCP_STATE_REBINDING:
1095
1096                 r = client_handle_ack(client, message, len);
1097                 if (r == DHCP_EVENT_NO_LEASE) {
1098
1099                         client->timeout_resend =
1100                                 sd_event_source_unref(client->timeout_resend);
1101
1102                         if (client->state == DHCP_STATE_REBOOTING) {
1103                                 r = client_initialize(client);
1104                                 if (r < 0)
1105                                         goto error;
1106
1107                                 r = client_start(client);
1108                                 if (r < 0)
1109                                         goto error;
1110
1111                                 log_dhcp_client(client, "REBOOTED");
1112                         }
1113
1114                         goto error;
1115                 } else if (r >= 0) {
1116                         client->timeout_resend =
1117                                 sd_event_source_unref(client->timeout_resend);
1118
1119                         if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1120                                    DHCP_STATE_REBOOTING))
1121                                 notify_event = DHCP_EVENT_IP_ACQUIRE;
1122                         else if (r != DHCP_EVENT_IP_ACQUIRE)
1123                                 notify_event = r;
1124
1125                         client->state = DHCP_STATE_BOUND;
1126                         client->attempt = 1;
1127
1128                         client->last_addr = client->lease->address;
1129
1130                         r = client_set_lease_timeouts(client);
1131                         if (r < 0)
1132                                 goto error;
1133
1134                         if (notify_event) {
1135                                 client = client_notify(client, notify_event);
1136                                 if (!client ||
1137                                     client->state == DHCP_STATE_STOPPED)
1138                                         return 0;
1139                         }
1140
1141                         client->receive_message =
1142                                 sd_event_source_unref(client->receive_message);
1143                         client->fd = safe_close(client->fd);
1144                 } else if (r == -ENOMSG)
1145                         /* invalid message, let's ignore it */
1146                         return 0;
1147
1148                 break;
1149
1150         case DHCP_STATE_INIT:
1151         case DHCP_STATE_INIT_REBOOT:
1152         case DHCP_STATE_BOUND:
1153
1154                 break;
1155
1156         case DHCP_STATE_STOPPED:
1157                 r = -EINVAL;
1158                 goto error;
1159         }
1160
1161 error:
1162         if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1163                 client_stop(client, r);
1164
1165         return r;
1166 }
1167
1168 static int client_receive_message_udp(sd_event_source *s, int fd,
1169                                       uint32_t revents, void *userdata) {
1170         sd_dhcp_client *client = userdata;
1171         _cleanup_free_ DHCPMessage *message = NULL;
1172         int buflen = 0, len, r;
1173
1174         assert(s);
1175         assert(client);
1176
1177         r = ioctl(fd, FIONREAD, &buflen);
1178         if (r < 0 || buflen <= 0)
1179                 buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE;
1180
1181         message = malloc0(buflen);
1182         if (!message)
1183                 return -ENOMEM;
1184
1185         len = read(fd, message, buflen);
1186         if (len < 0) {
1187                 log_dhcp_client(client, "could not receive message from UDP "
1188                                 "socket: %s", strerror(errno));
1189                 return 0;
1190         } else if ((size_t)len < sizeof(DHCPMessage))
1191                 return 0;
1192
1193         return client_handle_message(client, message, len);
1194 }
1195
1196 static int client_receive_message_raw(sd_event_source *s, int fd,
1197                                       uint32_t revents, void *userdata) {
1198         sd_dhcp_client *client = userdata;
1199         _cleanup_free_ DHCPPacket *packet = NULL;
1200         uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1201         struct iovec iov = {};
1202         struct msghdr msg = {
1203                 .msg_iov = &iov,
1204                 .msg_iovlen = 1,
1205                 .msg_control = cmsgbuf,
1206                 .msg_controllen = sizeof(cmsgbuf),
1207         };
1208         struct cmsghdr *cmsg;
1209         bool checksum = true;
1210         int buflen = 0, len, r;
1211
1212         assert(s);
1213         assert(client);
1214
1215         r = ioctl(fd, FIONREAD, &buflen);
1216         if (r < 0 || buflen <= 0)
1217                 buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE;
1218
1219         packet = malloc0(buflen);
1220         if (!packet)
1221                 return -ENOMEM;
1222
1223         iov.iov_base = packet;
1224         iov.iov_len = buflen;
1225
1226         len = recvmsg(fd, &msg, 0);
1227         if (len < 0) {
1228                 log_dhcp_client(client, "could not receive message from raw "
1229                                 "socket: %s", strerror(errno));
1230                 return 0;
1231         } else if ((size_t)len < sizeof(DHCPPacket))
1232                 return 0;
1233
1234         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1235                 if (cmsg->cmsg_level == SOL_PACKET &&
1236                     cmsg->cmsg_type == PACKET_AUXDATA &&
1237                     cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1238                         struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1239
1240                         checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1241                         break;
1242                 }
1243         }
1244
1245         r = dhcp_packet_verify_headers(packet, len, checksum);
1246         if (r < 0)
1247                 return 0;
1248
1249         len -= DHCP_IP_UDP_SIZE;
1250
1251         return client_handle_message(client, &packet->dhcp, len);
1252 }
1253
1254 int sd_dhcp_client_start(sd_dhcp_client *client) {
1255         int r;
1256
1257         assert_return(client, -EINVAL);
1258
1259         r = client_initialize(client);
1260         if (r < 0)
1261                 return r;
1262
1263         if (client->last_addr)
1264                 client->state = DHCP_STATE_INIT_REBOOT;
1265
1266         r = client_start(client);
1267         if (r >= 0)
1268                 log_dhcp_client(client, "STARTED on ifindex %u with address %s",
1269                                 client->index,
1270                                 ether_ntoa(&client->client_id.mac_addr));
1271
1272         return r;
1273 }
1274
1275 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1276         assert_return(client, -EINVAL);
1277
1278         if (client_stop(client, DHCP_EVENT_STOP))
1279                 client->state = DHCP_STATE_STOPPED;
1280
1281         return 0;
1282 }
1283
1284 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1285                                 int priority) {
1286         int r;
1287
1288         assert_return(client, -EINVAL);
1289         assert_return(!client->event, -EBUSY);
1290
1291         if (event)
1292                 client->event = sd_event_ref(event);
1293         else {
1294                 r = sd_event_default(&client->event);
1295                 if (r < 0)
1296                         return 0;
1297         }
1298
1299         client->event_priority = priority;
1300
1301         return 0;
1302 }
1303
1304 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1305         assert_return(client, -EINVAL);
1306
1307         client->event = sd_event_unref(client->event);
1308
1309         return 0;
1310 }
1311
1312 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1313         if (!client)
1314                 return NULL;
1315
1316         return client->event;
1317 }
1318
1319 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1320         if (client)
1321                 assert_se(REFCNT_INC(client->n_ref) >= 2);
1322
1323         return client;
1324 }
1325
1326 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1327         if (client && REFCNT_DEC(client->n_ref) <= 0) {
1328                 log_dhcp_client(client, "UNREF");
1329
1330                 client_initialize(client);
1331
1332                 client->receive_message =
1333                         sd_event_source_unref(client->receive_message);
1334
1335                 sd_dhcp_client_detach_event(client);
1336
1337                 sd_dhcp_lease_unref(client->lease);
1338
1339                 free(client->req_opts);
1340                 free(client);
1341
1342                 return NULL;
1343         }
1344
1345         return client;
1346 }
1347
1348 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
1349 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1350
1351 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1352         _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1353
1354         assert_return(ret, -EINVAL);
1355
1356         client = new0(sd_dhcp_client, 1);
1357         if (!client)
1358                 return -ENOMEM;
1359
1360         client->n_ref = REFCNT_INIT;
1361         client->state = DHCP_STATE_INIT;
1362         client->index = -1;
1363         client->fd = -1;
1364         client->attempt = 1;
1365
1366         client->req_opts_size = ELEMENTSOF(default_req_opts);
1367
1368         client->req_opts = memdup(default_req_opts, client->req_opts_size);
1369         if (!client->req_opts)
1370                 return -ENOMEM;
1371
1372         *ret = client;
1373         client = NULL;
1374
1375         return 0;
1376 }