2 This file is part of systemd.
4 Copyright (C) 2014 Axis Communications AB. All rights reserved.
5 Copyright (C) 2015 Tom Gundersen
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <arpa/inet.h>
27 #include "sd-ipv4acd.h"
29 #include "alloc-util.h"
31 #include "ether-addr-util.h"
33 #include "in-addr-util.h"
35 #include "random-util.h"
36 #include "siphash24.h"
37 #include "string-util.h"
40 /* Constants from the RFC */
45 #define ANNOUNCE_WAIT 2
46 #define ANNOUNCE_NUM 2
47 #define ANNOUNCE_INTERVAL 2
48 #define MAX_CONFLICTS 10
49 #define RATE_LIMIT_INTERVAL 60
50 #define DEFEND_INTERVAL 10
52 #define IPV4ACD_NETWORK 0xA9FE0000UL
53 #define IPV4ACD_NETMASK 0xFFFF0000UL
55 #define log_ipv4acd_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__)
56 #define log_ipv4acd(ll, fmt, ...) log_ipv4acd_errno(ll, 0, fmt, ##__VA_ARGS__)
58 typedef enum IPv4ACDState
{
60 IPV4ACD_STATE_STARTED
,
61 IPV4ACD_STATE_WAITING_PROBE
,
62 IPV4ACD_STATE_PROBING
,
63 IPV4ACD_STATE_WAITING_ANNOUNCE
,
64 IPV4ACD_STATE_ANNOUNCING
,
65 IPV4ACD_STATE_RUNNING
,
67 _IPV4ACD_STATE_INVALID
= -1
80 sd_event_source
*receive_message_event_source
;
81 sd_event_source
*timer_event_source
;
87 struct ether_addr mac_addr
;
91 sd_ipv4acd_callback_t callback
;
95 static void ipv4acd_set_state(sd_ipv4acd
*ll
, IPv4ACDState st
, bool reset_counter
) {
97 assert(st
< _IPV4ACD_STATE_MAX
);
99 if (st
== ll
->state
&& !reset_counter
)
107 static void ipv4acd_reset(sd_ipv4acd
*ll
) {
110 ll
->timer_event_source
= sd_event_source_unref(ll
->timer_event_source
);
111 ll
->receive_message_event_source
= sd_event_source_unref(ll
->receive_message_event_source
);
113 ll
->fd
= safe_close(ll
->fd
);
115 ipv4acd_set_state(ll
, IPV4ACD_STATE_INIT
, true);
118 sd_ipv4acd
*sd_ipv4acd_ref(sd_ipv4acd
*ll
) {
122 assert_se(ll
->n_ref
>= 1);
128 sd_ipv4acd
*sd_ipv4acd_unref(sd_ipv4acd
*ll
) {
132 assert_se(ll
->n_ref
>= 1);
139 sd_ipv4acd_detach_event(ll
);
146 int sd_ipv4acd_new(sd_ipv4acd
**ret
) {
147 _cleanup_(sd_ipv4acd_unrefp
) sd_ipv4acd
*ll
= NULL
;
149 assert_return(ret
, -EINVAL
);
151 ll
= new0(sd_ipv4acd
, 1);
156 ll
->state
= IPV4ACD_STATE_INIT
;
166 static void ipv4acd_client_notify(sd_ipv4acd
*ll
, int event
) {
172 ll
->callback(ll
, event
, ll
->userdata
);
175 int sd_ipv4acd_stop(sd_ipv4acd
*ll
) {
176 assert_return(ll
, -EINVAL
);
180 log_ipv4acd(ll
, "STOPPED");
182 ipv4acd_client_notify(ll
, SD_IPV4ACD_EVENT_STOP
);
187 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
);
189 static int ipv4acd_set_next_wakeup(sd_ipv4acd
*ll
, int sec
, int random_sec
) {
190 _cleanup_(sd_event_source_unrefp
) sd_event_source
*timer
= NULL
;
196 assert(random_sec
>= 0);
199 next_timeout
= sec
* USEC_PER_SEC
;
202 next_timeout
+= random_u32() % (random_sec
* USEC_PER_SEC
);
204 assert_se(sd_event_now(ll
->event
, clock_boottime_or_monotonic(), &time_now
) >= 0);
206 r
= sd_event_add_time(ll
->event
, &timer
, clock_boottime_or_monotonic(),
207 time_now
+ next_timeout
, 0, ipv4acd_on_timeout
, ll
);
211 r
= sd_event_source_set_priority(timer
, ll
->event_priority
);
215 (void) sd_event_source_set_description(timer
, "ipv4acd-timer");
217 sd_event_source_unref(ll
->timer_event_source
);
218 ll
->timer_event_source
= timer
;
224 static bool ipv4acd_arp_conflict(sd_ipv4acd
*ll
, struct ether_arp
*arp
) {
229 if (memcmp(arp
->arp_spa
, &ll
->address
, sizeof(ll
->address
)) == 0)
232 /* the TPA matched instead of the SPA, this is not a conflict */
236 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
237 sd_ipv4acd
*ll
= userdata
;
244 case IPV4ACD_STATE_STARTED
:
245 ipv4acd_set_state(ll
, IPV4ACD_STATE_WAITING_PROBE
, true);
247 if (ll
->n_conflict
>= MAX_CONFLICTS
) {
248 log_ipv4acd(ll
, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL
);
250 r
= ipv4acd_set_next_wakeup(ll
, RATE_LIMIT_INTERVAL
, PROBE_WAIT
);
256 r
= ipv4acd_set_next_wakeup(ll
, 0, PROBE_WAIT
);
263 case IPV4ACD_STATE_WAITING_PROBE
:
264 case IPV4ACD_STATE_PROBING
:
266 r
= arp_send_probe(ll
->fd
, ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
268 log_ipv4acd_errno(ll
, r
, "Failed to send ARP probe: %m");
271 _cleanup_free_
char *address
= NULL
;
272 union in_addr_union addr
= { .in
.s_addr
= ll
->address
};
274 (void) in_addr_to_string(AF_INET
, &addr
, &address
);
275 log_ipv4acd(ll
, "Probing %s", strna(address
));
278 if (ll
->n_iteration
< PROBE_NUM
- 2) {
279 ipv4acd_set_state(ll
, IPV4ACD_STATE_PROBING
, false);
281 r
= ipv4acd_set_next_wakeup(ll
, PROBE_MIN
, (PROBE_MAX
-PROBE_MIN
));
285 ipv4acd_set_state(ll
, IPV4ACD_STATE_WAITING_ANNOUNCE
, true);
287 r
= ipv4acd_set_next_wakeup(ll
, ANNOUNCE_WAIT
, 0);
294 case IPV4ACD_STATE_ANNOUNCING
:
295 if (ll
->n_iteration
>= ANNOUNCE_NUM
- 1) {
296 ipv4acd_set_state(ll
, IPV4ACD_STATE_RUNNING
, false);
302 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
303 /* Send announcement packet */
304 r
= arp_send_announcement(ll
->fd
, ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
306 log_ipv4acd_errno(ll
, r
, "Failed to send ARP announcement: %m");
309 log_ipv4acd(ll
, "ANNOUNCE");
311 ipv4acd_set_state(ll
, IPV4ACD_STATE_ANNOUNCING
, false);
313 r
= ipv4acd_set_next_wakeup(ll
, ANNOUNCE_INTERVAL
, 0);
317 if (ll
->n_iteration
== 0) {
319 ipv4acd_client_notify(ll
, SD_IPV4ACD_EVENT_BIND
);
325 assert_not_reached("Invalid state.");
335 static void ipv4acd_on_conflict(sd_ipv4acd
*ll
) {
336 _cleanup_free_
char *address
= NULL
;
337 union in_addr_union addr
= { .in
.s_addr
= ll
->address
};
343 (void) in_addr_to_string(AF_INET
, &addr
, &address
);
344 log_ipv4acd(ll
, "Conflict on %s (%u)", strna(address
), ll
->n_conflict
);
347 ipv4acd_client_notify(ll
, SD_IPV4ACD_EVENT_CONFLICT
);
350 static int ipv4acd_on_packet(
356 sd_ipv4acd
*ll
= userdata
;
357 struct ether_arp packet
;
365 n
= recv(fd
, &packet
, sizeof(struct ether_arp
), 0);
367 if (errno
== EAGAIN
|| errno
== EINTR
)
370 r
= log_ipv4acd_errno(ll
, errno
, "Failed to read ARP packet: %m");
373 if ((size_t) n
!= sizeof(struct ether_arp
)) {
374 log_ipv4acd(ll
, "Ignoring too short ARP packet.");
380 case IPV4ACD_STATE_ANNOUNCING
:
381 case IPV4ACD_STATE_RUNNING
:
383 if (ipv4acd_arp_conflict(ll
, &packet
)) {
386 assert_se(sd_event_now(ll
->event
, clock_boottime_or_monotonic(), &ts
) >= 0);
389 if (ts
> ll
->defend_window
) {
390 ll
->defend_window
= ts
+ DEFEND_INTERVAL
* USEC_PER_SEC
;
391 r
= arp_send_announcement(ll
->fd
, ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
393 log_ipv4acd_errno(ll
, r
, "Failed to send ARP announcement: %m");
396 log_ipv4acd(ll
, "DEFEND");
399 ipv4acd_on_conflict(ll
);
403 case IPV4ACD_STATE_WAITING_PROBE
:
404 case IPV4ACD_STATE_PROBING
:
405 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
406 /* BPF ensures this packet indicates a conflict */
407 ipv4acd_on_conflict(ll
);
411 assert_not_reached("Invalid state.");
421 int sd_ipv4acd_set_ifindex(sd_ipv4acd
*ll
, int ifindex
) {
422 assert_return(ll
, -EINVAL
);
423 assert_return(ifindex
> 0, -EINVAL
);
424 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
426 ll
->ifindex
= ifindex
;
431 int sd_ipv4acd_set_mac(sd_ipv4acd
*ll
, const struct ether_addr
*addr
) {
432 assert_return(ll
, -EINVAL
);
433 assert_return(addr
, -EINVAL
);
434 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
436 memcpy(&ll
->mac_addr
, addr
, ETH_ALEN
);
441 int sd_ipv4acd_detach_event(sd_ipv4acd
*ll
) {
442 assert_return(ll
, -EINVAL
);
444 ll
->event
= sd_event_unref(ll
->event
);
449 int sd_ipv4acd_attach_event(sd_ipv4acd
*ll
, sd_event
*event
, int64_t priority
) {
452 assert_return(ll
, -EINVAL
);
453 assert_return(!ll
->event
, -EBUSY
);
456 ll
->event
= sd_event_ref(event
);
458 r
= sd_event_default(&ll
->event
);
463 ll
->event_priority
= priority
;
468 int sd_ipv4acd_set_callback(sd_ipv4acd
*ll
, sd_ipv4acd_callback_t cb
, void *userdata
) {
469 assert_return(ll
, -EINVAL
);
472 ll
->userdata
= userdata
;
477 int sd_ipv4acd_set_address(sd_ipv4acd
*ll
, const struct in_addr
*address
) {
478 assert_return(ll
, -EINVAL
);
479 assert_return(address
, -EINVAL
);
480 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
482 ll
->address
= address
->s_addr
;
487 int sd_ipv4acd_is_running(sd_ipv4acd
*ll
) {
488 assert_return(ll
, false);
490 return ll
->state
!= IPV4ACD_STATE_INIT
;
493 int sd_ipv4acd_start(sd_ipv4acd
*ll
) {
496 assert_return(ll
, -EINVAL
);
497 assert_return(ll
->event
, -EINVAL
);
498 assert_return(ll
->ifindex
> 0, -EINVAL
);
499 assert_return(ll
->address
!= 0, -EINVAL
);
500 assert_return(!ether_addr_is_null(&ll
->mac_addr
), -EINVAL
);
501 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
503 r
= arp_network_bind_raw_socket(ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
509 ll
->defend_window
= 0;
511 r
= sd_event_add_io(ll
->event
, &ll
->receive_message_event_source
, ll
->fd
, EPOLLIN
, ipv4acd_on_packet
, ll
);
515 r
= sd_event_source_set_priority(ll
->receive_message_event_source
, ll
->event_priority
);
519 (void) sd_event_source_set_description(ll
->receive_message_event_source
, "ipv4acd-receive-message");
521 r
= ipv4acd_set_next_wakeup(ll
, 0, 0);
525 ipv4acd_set_state(ll
, IPV4ACD_STATE_STARTED
, true);