chiark / gitweb /
689dce9adffba972f5996106dbfed22c4d0ae275
[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 "list.h"
28
29 #include "ipv4ll-internal.h"
30 #include "sd-ipv4ll.h"
31
32 /* Constants from the RFC */
33 #define PROBE_WAIT 1
34 #define PROBE_NUM 3
35 #define PROBE_MIN 1
36 #define PROBE_MAX 2
37 #define ANNOUNCE_WAIT 2
38 #define ANNOUNCE_NUM 2
39 #define ANNOUNCE_INTERVAL 2
40 #define MAX_CONFLICTS 10
41 #define RATE_LIMIT_INTERVAL 60
42 #define DEFEND_INTERVAL 10
43
44 #define IPV4LL_NETWORK 0xA9FE0000L
45 #define IPV4LL_NETMASK 0xFFFF0000L
46
47 typedef enum IPv4LLTrigger{
48         IPV4LL_TRIGGER_NULL,
49         IPV4LL_TRIGGER_PACKET,
50         IPV4LL_TRIGGER_TIMEOUT,
51         _IPV4LL_TRIGGER_MAX,
52         _IPV4LL_TRIGGER_INVALID = -1
53 } IPv4LLTrigger;
54
55 typedef enum IPv4LLState {
56         IPV4LL_STATE_INIT,
57         IPV4LL_STATE_WAITING_PROBE,
58         IPV4LL_STATE_PROBING,
59         IPV4LL_STATE_WAITING_ANNOUNCE,
60         IPV4LL_STATE_ANNOUNCING,
61         IPV4LL_STATE_RUNNING,
62         _IPV4LL_STATE_MAX,
63         _IPV4LL_STATE_INVALID = -1
64 } IPv4LLState;
65
66 struct sd_ipv4ll {
67         IPv4LLState state;
68         int index;
69         int fd;
70         union sockaddr_union link;
71         int iteration;
72         int conflict;
73         sd_event_source *receive_message;
74         sd_event_source *timer;
75         usec_t next_wakeup;
76         usec_t defend_window;
77         int next_wakeup_valid;
78         be32_t address;
79         /* External */
80         be32_t claimed_address;
81         struct ether_addr mac_addr;
82         sd_event *event;
83         int event_priority;
84         sd_ipv4ll_cb_t cb;
85         void* userdata;
86 };
87
88 static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data);
89
90 static void ipv4ll_set_state(sd_ipv4ll *ll, IPv4LLState st, int reset_counter) {
91
92         assert(ll);
93         assert(st < _IPV4LL_STATE_MAX);
94
95         if (st == ll->state && !reset_counter) {
96                 ll->iteration++;
97         } else {
98                 ll->state = st;
99                 ll->iteration = 0;
100         }
101 }
102
103 static int ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
104         assert(ll);
105
106         if (ll->cb)
107                 ll->cb(ll, event, ll->userdata);
108
109         return 0;
110 }
111
112 static int ipv4ll_stop(sd_ipv4ll *ll, int event) {
113         assert(ll);
114
115         ll->receive_message = sd_event_source_unref(ll->receive_message);
116         ll->fd = safe_close(ll->fd);
117
118         ll->timer = sd_event_source_unref(ll->timer);
119
120         ipv4ll_client_notify(ll, event);
121
122         ll->claimed_address = 0;
123
124         ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
125
126         log_ipv4ll(ll, "STOPPED");
127
128         return 0;
129 }
130
131 static be32_t ipv4ll_pick_address(sd_ipv4ll *ll) {
132         be32_t addr;
133
134         assert(ll);
135
136         if (ll->address) {
137                 do {
138                         uint32_t r = random_u32() & 0x0000FFFF;
139                         addr = htonl(IPV4LL_NETWORK | r);
140                 } while (addr == ll->address ||
141                         (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
142                         (ntohl(addr) & 0x0000FF00) == 0x0000 ||
143                         (ntohl(addr) & 0x0000FF00) == 0xFF00);
144         } else {
145                 uint32_t a = 1;
146                 int i;
147
148                 for (i = 0; i < ETH_ALEN; i++)
149                         a += ll->mac_addr.ether_addr_octet[i]*i;
150                 a = (a % 0xFE00) + 0x0100;
151                 addr = htonl(IPV4LL_NETWORK | (uint32_t) a);
152         }
153
154         return addr;
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_get_now_monotonic(ll->event, &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_get_now_monotonic(ll->event, &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                         ll->address = ipv4ll_pick_address(ll);
308                         ll->conflict++;
309                         ll->defend_window = 0;
310                         ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
311
312                         if (ll->conflict >= MAX_CONFLICTS) {
313                                 log_ipv4ll(ll, "MAX_CONFLICTS");
314                                 ipv4ll_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
315                         } else
316                                 ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
317
318                 }
319         }
320
321         if (out_packet_ready) {
322                 r = arp_network_send_raw_socket(ll->fd, &ll->link, &out_packet);
323                 if (r < 0) {
324                         log_ipv4ll(ll, "failed to send arp packet out");
325                         goto out;
326                 }
327         }
328
329         if (ll->next_wakeup_valid) {
330                 ll->timer = sd_event_source_unref(ll->timer);
331                 r = sd_event_add_monotonic(ll->event, &ll->timer,
332                                    ll->next_wakeup, 0, ipv4ll_timer, ll);
333                 if (r < 0)
334                         goto out;
335
336                 r = sd_event_source_set_priority(ll->timer, ll->event_priority);
337                 if (r < 0)
338                         goto out;
339         }
340
341 out:
342         if (r < 0)
343                 ipv4ll_stop(ll, r);
344 }
345
346 static int ipv4ll_receive_message(sd_event_source *s, int fd,
347                                   uint32_t revents, void *userdata) {
348         int r;
349         struct ether_arp arp;
350         sd_ipv4ll *ll = (sd_ipv4ll*)userdata;
351
352         assert(ll);
353
354         r = read(fd, &arp, sizeof(struct ether_arp));
355         if (r < (int) sizeof(struct ether_arp))
356                 return 0;
357
358         r = arp_packet_verify_headers(&arp);
359         if (r < 0)
360                 return 0;
361
362         ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_PACKET, &arp);
363
364         return 0;
365 }
366
367 int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index) {
368         assert_return(ll, -EINVAL);
369         assert_return(interface_index >= -1, -EINVAL);
370         assert_return(ll->state == IPV4LL_STATE_INIT, -EBUSY);
371
372         ll->index = interface_index;
373
374         return 0;
375 }
376
377 int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
378         assert_return(ll, -EINVAL);
379         assert_return(ll->state == IPV4LL_STATE_INIT, -EBUSY);
380
381         memcpy(&ll->mac_addr.ether_addr_octet, addr, ETH_ALEN);
382
383         return 0;
384 }
385
386 int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
387         assert_return(ll, -EINVAL);
388
389         ll->event = sd_event_unref(ll->event);
390
391         return 0;
392 }
393
394 int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
395         int r;
396
397         assert_return(ll, -EINVAL);
398         assert_return(!ll->event, -EBUSY);
399
400         if (event)
401                 ll->event = sd_event_ref(event);
402         else {
403                 r = sd_event_default(&ll->event);
404                 if (r < 0) {
405                         ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
406                         return r;
407                 }
408         }
409
410         ll->event_priority = priority;
411
412         return 0;
413 }
414
415 int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) {
416         assert_return(ll, -EINVAL);
417
418         ll->cb = cb;
419         ll->userdata = userdata;
420
421         return 0;
422 }
423
424 int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){
425         assert_return(ll, -EINVAL);
426         assert_return(address, -EINVAL);
427
428         if (ll->claimed_address == 0) {
429                 return -ENOENT;
430         }
431
432         address->s_addr = ll->claimed_address;
433         return 0;
434 }
435
436 int sd_ipv4ll_start (sd_ipv4ll *ll) {
437         int r;
438
439         assert_return(ll, -EINVAL);
440         assert_return(ll->event, -EINVAL);
441         assert_return(ll->index > 0, -EINVAL);
442         assert_return(ll->state == IPV4LL_STATE_INIT, -EBUSY);
443
444         r = arp_network_bind_raw_socket(ll->index, &ll->link);
445
446         if (r < 0)
447                 goto out;
448
449         ll->fd = r;
450         ll->conflict = 0;
451         ll->defend_window = 0;
452         ll->claimed_address = 0;
453
454         if (ll->address == 0)
455                 ll->address = ipv4ll_pick_address(ll);
456
457         ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
458
459         r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd,
460                             EPOLLIN, ipv4ll_receive_message, ll);
461         if (r < 0)
462                 goto out;
463
464         r = sd_event_source_set_priority(ll->receive_message, ll->event_priority);
465         if (r < 0)
466                 goto out;
467
468         r = sd_event_add_monotonic(ll->event, &ll->timer, now(CLOCK_MONOTONIC), 0,
469                                    ipv4ll_timer, ll);
470
471         if (r < 0)
472                 goto out;
473
474         r = sd_event_source_set_priority(ll->timer, ll->event_priority);
475
476 out:
477         if (r < 0)
478                 ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
479
480         return 0;
481 }
482
483 int sd_ipv4ll_stop(sd_ipv4ll *ll) {
484         return ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
485 }
486
487 void sd_ipv4ll_free (sd_ipv4ll *ll) {
488         if (!ll)
489                 return;
490
491         sd_ipv4ll_stop(ll);
492         sd_ipv4ll_detach_event(ll);
493
494         free(ll);
495 }
496
497 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_free);
498 #define _cleanup_ipv4ll_free_ _cleanup_(sd_ipv4ll_freep)
499
500 int sd_ipv4ll_new(sd_ipv4ll **ret) {
501         _cleanup_ipv4ll_free_ sd_ipv4ll *ll = NULL;
502
503         assert_return(ret, -EINVAL);
504
505         ll = new0(sd_ipv4ll, 1);
506         if (!ll)
507                 return -ENOMEM;
508
509         ll->state = IPV4LL_STATE_INIT;
510         ll->index = -1;
511         ll->fd = -1;
512
513         *ret = ll;
514         ll = NULL;
515
516         return 0;
517 }