chiark / gitweb /
sd-event: rework API to support CLOCK_REALTIME_ALARM and CLOCK_BOOTTIME_ALARM, too
[elogind.git] / src / libsystemd-network / sd-ipv4ll.c
1 /***
2   This file is part of systemd.
3
4   Copyright (C) 2014 Axis Communications AB. 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 <arpa/inet.h>
25
26 #include "util.h"
27 #include "siphash24.h"
28 #include "list.h"
29
30 #include "ipv4ll-internal.h"
31 #include "sd-ipv4ll.h"
32
33 /* Constants from the RFC */
34 #define PROBE_WAIT 1
35 #define PROBE_NUM 3
36 #define PROBE_MIN 1
37 #define PROBE_MAX 2
38 #define ANNOUNCE_WAIT 2
39 #define ANNOUNCE_NUM 2
40 #define ANNOUNCE_INTERVAL 2
41 #define MAX_CONFLICTS 10
42 #define RATE_LIMIT_INTERVAL 60
43 #define DEFEND_INTERVAL 10
44
45 #define IPV4LL_NETWORK 0xA9FE0000L
46 #define IPV4LL_NETMASK 0xFFFF0000L
47
48 typedef enum IPv4LLTrigger{
49         IPV4LL_TRIGGER_NULL,
50         IPV4LL_TRIGGER_PACKET,
51         IPV4LL_TRIGGER_TIMEOUT,
52         _IPV4LL_TRIGGER_MAX,
53         _IPV4LL_TRIGGER_INVALID = -1
54 } IPv4LLTrigger;
55
56 typedef enum IPv4LLState {
57         IPV4LL_STATE_INIT,
58         IPV4LL_STATE_WAITING_PROBE,
59         IPV4LL_STATE_PROBING,
60         IPV4LL_STATE_WAITING_ANNOUNCE,
61         IPV4LL_STATE_ANNOUNCING,
62         IPV4LL_STATE_RUNNING,
63         _IPV4LL_STATE_MAX,
64         _IPV4LL_STATE_INVALID = -1
65 } IPv4LLState;
66
67 struct sd_ipv4ll {
68         IPv4LLState state;
69         int index;
70         int fd;
71         union sockaddr_union link;
72         int iteration;
73         int conflict;
74         sd_event_source *receive_message;
75         sd_event_source *timer;
76         usec_t next_wakeup;
77         usec_t defend_window;
78         int next_wakeup_valid;
79         be32_t address;
80         struct random_data *random_data;
81         char *random_data_state;
82         /* External */
83         be32_t claimed_address;
84         struct ether_addr mac_addr;
85         sd_event *event;
86         int event_priority;
87         sd_ipv4ll_cb_t cb;
88         void* userdata;
89 };
90
91 static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data);
92
93 static void ipv4ll_set_state(sd_ipv4ll *ll, IPv4LLState st, int reset_counter) {
94
95         assert(ll);
96         assert(st < _IPV4LL_STATE_MAX);
97
98         if (st == ll->state && !reset_counter) {
99                 ll->iteration++;
100         } else {
101                 ll->state = st;
102                 ll->iteration = 0;
103         }
104 }
105
106 static int ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
107         assert(ll);
108
109         if (ll->cb)
110                 ll->cb(ll, event, ll->userdata);
111
112         return 0;
113 }
114
115 static int ipv4ll_stop(sd_ipv4ll *ll, int event) {
116         assert(ll);
117
118         ll->receive_message = sd_event_source_unref(ll->receive_message);
119         ll->fd = safe_close(ll->fd);
120
121         ll->timer = sd_event_source_unref(ll->timer);
122
123         ipv4ll_client_notify(ll, event);
124
125         ll->claimed_address = 0;
126
127         ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
128
129         log_ipv4ll(ll, "STOPPED");
130
131         return 0;
132 }
133
134 static int ipv4ll_pick_address(sd_ipv4ll *ll, be32_t *address) {
135         be32_t addr;
136         int r;
137         int32_t random;
138
139         assert(ll);
140         assert(address);
141         assert(ll->random_data);
142
143         do {
144                 r = random_r(ll->random_data, &random);
145                 if (r < 0)
146                         return r;
147                 addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
148         } while (addr == ll->address ||
149                 (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
150                 (ntohl(addr) & 0x0000FF00) == 0x0000 ||
151                 (ntohl(addr) & 0x0000FF00) == 0xFF00);
152
153         *address = addr;
154         return 0;
155 }
156
157 static int ipv4ll_timer(sd_event_source *s, uint64_t usec, void *userdata) {
158         sd_ipv4ll *ll = (sd_ipv4ll*)userdata;
159
160         assert(ll);
161
162         ll->next_wakeup_valid = 0;
163         ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_TIMEOUT, NULL);
164
165         return 0;
166 }
167
168 static void ipv4ll_set_next_wakeup(sd_ipv4ll *ll, int sec, int random_sec) {
169         usec_t next_timeout = 0;
170         usec_t time_now = 0;
171
172         assert(sec >= 0);
173         assert(random_sec >= 0);
174         assert(ll);
175
176         next_timeout = sec * USEC_PER_SEC;
177
178         if (random_sec)
179                 next_timeout += random_u32() % (random_sec * USEC_PER_SEC);
180
181         if (sd_event_now(ll->event, CLOCK_MONOTONIC, &time_now) < 0)
182                 time_now = now(CLOCK_MONOTONIC);
183
184         ll->next_wakeup = time_now + next_timeout;
185         ll->next_wakeup_valid = 1;
186 }
187
188 static bool ipv4ll_arp_conflict (sd_ipv4ll *ll, struct ether_arp *arp) {
189         assert(ll);
190         assert(arp);
191
192         if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0 &&
193             memcmp(arp->arp_sha, &ll->mac_addr, ETH_ALEN) != 0)
194                 return true;
195
196         return false;
197 }
198
199 static bool ipv4ll_arp_probe_conflict (sd_ipv4ll *ll, struct ether_arp *arp) {
200         assert(ll);
201         assert(arp);
202
203         if (ipv4ll_arp_conflict(ll, arp))
204                 return true;
205
206         if (memcmp(arp->arp_tpa, &ll->address, sizeof(ll->address)) == 0 &&
207             memcmp(arp->arp_sha, &ll->mac_addr, ETH_ALEN))
208                 return true;
209
210         return false;
211 }
212
213 static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data) {
214         struct ether_arp out_packet;
215         int out_packet_ready = 0;
216         int r = 0;
217
218         assert(ll);
219         assert(trigger < _IPV4LL_TRIGGER_MAX);
220
221         if (ll->state == IPV4LL_STATE_INIT) {
222
223                 log_ipv4ll(ll, "PROBE");
224                 ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
225                 ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
226
227         } else if ((ll->state == IPV4LL_STATE_WAITING_PROBE && trigger == IPV4LL_TRIGGER_TIMEOUT) ||
228                 (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < PROBE_NUM-2)) {
229
230                 /* Send a probe */
231                 arp_packet_probe(&out_packet, ll->address, &ll->mac_addr);
232                 out_packet_ready = 1;
233                 ipv4ll_set_state(ll, IPV4LL_STATE_PROBING, 0);
234
235                 ipv4ll_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN));
236
237         } else if (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration >= PROBE_NUM-2) {
238
239                 /* Send the last probe */
240                 arp_packet_probe(&out_packet, ll->address, &ll->mac_addr);
241                 out_packet_ready = 1;
242                 ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_ANNOUNCE, 1);
243
244                 ipv4ll_set_next_wakeup(ll, ANNOUNCE_WAIT, 0);
245
246         } else if ((ll->state == IPV4LL_STATE_WAITING_ANNOUNCE && trigger == IPV4LL_TRIGGER_TIMEOUT) ||
247                 (ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < ANNOUNCE_NUM-1)) {
248
249                 /* Send announcement packet */
250                 arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr);
251                 out_packet_ready = 1;
252                 ipv4ll_set_state(ll, IPV4LL_STATE_ANNOUNCING, 0);
253
254                 ipv4ll_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0);
255
256                 if (ll->iteration == 0) {
257                         log_ipv4ll(ll, "ANNOUNCE");
258                         ll->claimed_address = ll->address;
259                         r = ipv4ll_client_notify(ll, IPV4LL_EVENT_BIND);
260                         ll->conflict = 0;
261                 }
262
263         } else if ((ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT &&
264                     ll->iteration >= ANNOUNCE_NUM-1)) {
265
266                 ipv4ll_set_state(ll, IPV4LL_STATE_RUNNING, 0);
267                 ll->next_wakeup_valid = 0;
268
269         } else if (trigger == IPV4LL_TRIGGER_PACKET) {
270
271                 int conflicted = 0;
272                 usec_t time_now;
273                 struct ether_arp* in_packet = (struct ether_arp*)trigger_data;
274
275                 assert(in_packet);
276
277                 if (IN_SET(ll->state, IPV4LL_STATE_ANNOUNCING, IPV4LL_STATE_RUNNING)) {
278
279                         if (ipv4ll_arp_conflict(ll, in_packet)) {
280
281                                 r = sd_event_now(ll->event, CLOCK_MONOTONIC, &time_now);
282                                 if (r < 0)
283                                         goto out;
284
285                                 /* Defend address */
286                                 if (time_now > ll->defend_window) {
287                                         ll->defend_window = time_now + DEFEND_INTERVAL * USEC_PER_SEC;
288                                         arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr);
289                                         out_packet_ready = 1;
290                                 } else
291                                         conflicted = 1;
292                         }
293
294                 } else if (IN_SET(ll->state, IPV4LL_STATE_WAITING_PROBE,
295                                              IPV4LL_STATE_PROBING,
296                                              IPV4LL_STATE_WAITING_ANNOUNCE)) {
297
298                         conflicted = ipv4ll_arp_probe_conflict(ll, in_packet);
299                 }
300
301                 if (conflicted) {
302                         log_ipv4ll(ll, "CONFLICT");
303                         r = ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT);
304                         ll->claimed_address = 0;
305
306                         /* Pick a new address */
307                         r = ipv4ll_pick_address(ll, &ll->address);
308                         if (r < 0)
309                                 goto out;
310                         ll->conflict++;
311                         ll->defend_window = 0;
312                         ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
313
314                         if (ll->conflict >= MAX_CONFLICTS) {
315                                 log_ipv4ll(ll, "MAX_CONFLICTS");
316                                 ipv4ll_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
317                         } else
318                                 ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
319
320                 }
321         }
322
323         if (out_packet_ready) {
324                 r = arp_network_send_raw_socket(ll->fd, &ll->link, &out_packet);
325                 if (r < 0) {
326                         log_ipv4ll(ll, "failed to send arp packet out");
327                         goto out;
328                 }
329         }
330
331         if (ll->next_wakeup_valid) {
332                 ll->timer = sd_event_source_unref(ll->timer);
333                 r = sd_event_add_time(ll->event, &ll->timer, CLOCK_MONOTONIC,
334                                       ll->next_wakeup, 0, ipv4ll_timer, ll);
335                 if (r < 0)
336                         goto out;
337
338                 r = sd_event_source_set_priority(ll->timer, ll->event_priority);
339                 if (r < 0)
340                         goto out;
341         }
342
343 out:
344         if (r < 0)
345                 ipv4ll_stop(ll, r);
346 }
347
348 static int ipv4ll_receive_message(sd_event_source *s, int fd,
349                                   uint32_t revents, void *userdata) {
350         int r;
351         struct ether_arp arp;
352         sd_ipv4ll *ll = (sd_ipv4ll*)userdata;
353
354         assert(ll);
355
356         r = read(fd, &arp, sizeof(struct ether_arp));
357         if (r < (int) sizeof(struct ether_arp))
358                 return 0;
359
360         r = arp_packet_verify_headers(&arp);
361         if (r < 0)
362                 return 0;
363
364         ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_PACKET, &arp);
365
366         return 0;
367 }
368
369 int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index) {
370         assert_return(ll, -EINVAL);
371         assert_return(interface_index >= -1, -EINVAL);
372         assert_return(ll->state == IPV4LL_STATE_INIT, -EBUSY);
373
374         ll->index = interface_index;
375
376         return 0;
377 }
378
379 int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
380         bool need_restart = false;
381
382         assert_return(ll, -EINVAL);
383         assert_return(addr, -EINVAL);
384
385         if (memcmp(&ll->mac_addr, addr, ETH_ALEN) == 0)
386                 return 0;
387
388         if (ll->state != IPV4LL_STATE_INIT) {
389                 log_ipv4ll(ll, "Changing MAC address on running IPv4LL "
390                            "client, restarting");
391                 sd_ipv4ll_stop(ll);
392                 need_restart = true;
393         }
394
395         memcpy(&ll->mac_addr, addr, ETH_ALEN);
396
397         if (need_restart)
398                 sd_ipv4ll_start(ll);
399
400         return 0;
401 }
402
403 int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
404         assert_return(ll, -EINVAL);
405
406         ll->event = sd_event_unref(ll->event);
407
408         return 0;
409 }
410
411 int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
412         int r;
413
414         assert_return(ll, -EINVAL);
415         assert_return(!ll->event, -EBUSY);
416
417         if (event)
418                 ll->event = sd_event_ref(event);
419         else {
420                 r = sd_event_default(&ll->event);
421                 if (r < 0) {
422                         ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
423                         return r;
424                 }
425         }
426
427         ll->event_priority = priority;
428
429         return 0;
430 }
431
432 int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) {
433         assert_return(ll, -EINVAL);
434
435         ll->cb = cb;
436         ll->userdata = userdata;
437
438         return 0;
439 }
440
441 int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){
442         assert_return(ll, -EINVAL);
443         assert_return(address, -EINVAL);
444
445         if (ll->claimed_address == 0) {
446                 return -ENOENT;
447         }
448
449         address->s_addr = ll->claimed_address;
450         return 0;
451 }
452
453 int sd_ipv4ll_set_address_seed (sd_ipv4ll *ll, uint8_t seed[8]) {
454         unsigned int entropy = *seed;
455         int r;
456
457         assert_return(ll, -EINVAL);
458
459         free(ll->random_data);
460         free(ll->random_data_state);
461
462         ll->random_data = new0(struct random_data, 1);
463         ll->random_data_state = new0(char, 128);
464
465         if (!ll->random_data || !ll->random_data_state) {
466                 r = -ENOMEM;
467                 goto error;
468         }
469
470         r = initstate_r((unsigned int)entropy, ll->random_data_state, 128, ll->random_data);
471         if (r < 0)
472                 goto error;
473
474 error:
475         if (r < 0){
476                 free(ll->random_data);
477                 free(ll->random_data_state);
478                 ll->random_data = NULL;
479                 ll->random_data_state = NULL;
480         }
481         return r;
482 }
483
484 #define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
485
486 int sd_ipv4ll_start (sd_ipv4ll *ll) {
487         int r;
488
489         assert_return(ll, -EINVAL);
490         assert_return(ll->event, -EINVAL);
491         assert_return(ll->index > 0, -EINVAL);
492         assert_return(ll->state == IPV4LL_STATE_INIT, -EBUSY);
493
494         r = arp_network_bind_raw_socket(ll->index, &ll->link);
495
496         if (r < 0)
497                 goto out;
498
499         ll->fd = r;
500         ll->conflict = 0;
501         ll->defend_window = 0;
502         ll->claimed_address = 0;
503
504         if (!ll->random_data) {
505                 uint8_t seed[8];
506
507                 /* Fallback to mac */
508                 siphash24(seed, &ll->mac_addr.ether_addr_octet,
509                           ETH_ALEN, HASH_KEY.bytes);
510
511                 r = sd_ipv4ll_set_address_seed(ll, seed);
512                 if (r < 0)
513                         goto out;
514         }
515
516         if (ll->address == 0) {
517                 r = ipv4ll_pick_address(ll, &ll->address);
518                 if (r < 0)
519                         goto out;
520         }
521
522         ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
523
524         r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd,
525                             EPOLLIN, ipv4ll_receive_message, ll);
526         if (r < 0)
527                 goto out;
528
529         r = sd_event_source_set_priority(ll->receive_message, ll->event_priority);
530         if (r < 0)
531                 goto out;
532
533         r = sd_event_add_time(ll->event,
534                               &ll->timer,
535                               CLOCK_MONOTONIC,
536                               now(CLOCK_MONOTONIC), 0,
537                               ipv4ll_timer, ll);
538
539         if (r < 0)
540                 goto out;
541
542         r = sd_event_source_set_priority(ll->timer, ll->event_priority);
543
544 out:
545         if (r < 0)
546                 ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
547
548         return 0;
549 }
550
551 int sd_ipv4ll_stop(sd_ipv4ll *ll) {
552         return ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
553 }
554
555 void sd_ipv4ll_free (sd_ipv4ll *ll) {
556         if (!ll)
557                 return;
558
559         sd_ipv4ll_stop(ll);
560         sd_ipv4ll_detach_event(ll);
561
562         free(ll->random_data);
563         free(ll->random_data_state);
564         free(ll);
565 }
566
567 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_free);
568 #define _cleanup_ipv4ll_free_ _cleanup_(sd_ipv4ll_freep)
569
570 int sd_ipv4ll_new(sd_ipv4ll **ret) {
571         _cleanup_ipv4ll_free_ sd_ipv4ll *ll = NULL;
572
573         assert_return(ret, -EINVAL);
574
575         ll = new0(sd_ipv4ll, 1);
576         if (!ll)
577                 return -ENOMEM;
578
579         ll->state = IPV4LL_STATE_INIT;
580         ll->index = -1;
581         ll->fd = -1;
582
583         *ret = ll;
584         ll = NULL;
585
586         return 0;
587 }