1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright (C) 2014 Axis Communications AB. All rights reserved.
4 Copyright (C) 2015 Tom Gundersen
13 #include "sd-ipv4acd.h"
15 #include "alloc-util.h"
17 #include "ether-addr-util.h"
19 #include "in-addr-util.h"
21 #include "random-util.h"
22 #include "siphash24.h"
23 #include "string-util.h"
26 /* Constants from the RFC */
27 #define PROBE_WAIT_USEC (1U * USEC_PER_SEC)
29 #define PROBE_MIN_USEC (1U * USEC_PER_SEC)
30 #define PROBE_MAX_USEC (2U * USEC_PER_SEC)
31 #define ANNOUNCE_WAIT_USEC (2U * USEC_PER_SEC)
32 #define ANNOUNCE_NUM 2U
33 #define ANNOUNCE_INTERVAL_USEC (2U * USEC_PER_SEC)
34 #define MAX_CONFLICTS 10U
35 #define RATE_LIMIT_INTERVAL_USEC (60U * USEC_PER_SEC)
36 #define DEFEND_INTERVAL_USEC (10U * USEC_PER_SEC)
38 typedef enum IPv4ACDState
{
40 IPV4ACD_STATE_STARTED
,
41 IPV4ACD_STATE_WAITING_PROBE
,
42 IPV4ACD_STATE_PROBING
,
43 IPV4ACD_STATE_WAITING_ANNOUNCE
,
44 IPV4ACD_STATE_ANNOUNCING
,
45 IPV4ACD_STATE_RUNNING
,
47 _IPV4ACD_STATE_INVALID
= -1
60 sd_event_source
*receive_message_event_source
;
61 sd_event_source
*timer_event_source
;
67 struct ether_addr mac_addr
;
71 sd_ipv4acd_callback_t callback
;
75 #define log_ipv4acd_errno(acd, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__)
76 #define log_ipv4acd(acd, fmt, ...) log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__)
78 static void ipv4acd_set_state(sd_ipv4acd
*acd
, IPv4ACDState st
, bool reset_counter
) {
80 assert(st
< _IPV4ACD_STATE_MAX
);
82 if (st
== acd
->state
&& !reset_counter
)
90 static void ipv4acd_reset(sd_ipv4acd
*acd
) {
93 acd
->timer_event_source
= sd_event_source_unref(acd
->timer_event_source
);
94 acd
->receive_message_event_source
= sd_event_source_unref(acd
->receive_message_event_source
);
96 acd
->fd
= safe_close(acd
->fd
);
98 ipv4acd_set_state(acd
, IPV4ACD_STATE_INIT
, true);
101 sd_ipv4acd
*sd_ipv4acd_ref(sd_ipv4acd
*acd
) {
105 assert_se(acd
->n_ref
>= 1);
111 sd_ipv4acd
*sd_ipv4acd_unref(sd_ipv4acd
*acd
) {
115 assert_se(acd
->n_ref
>= 1);
122 sd_ipv4acd_detach_event(acd
);
127 int sd_ipv4acd_new(sd_ipv4acd
**ret
) {
128 _cleanup_(sd_ipv4acd_unrefp
) sd_ipv4acd
*acd
= NULL
;
130 assert_return(ret
, -EINVAL
);
132 acd
= new0(sd_ipv4acd
, 1);
137 acd
->state
= IPV4ACD_STATE_INIT
;
141 *ret
= TAKE_PTR(acd
);
146 static void ipv4acd_client_notify(sd_ipv4acd
*acd
, int event
) {
152 acd
->callback(acd
, event
, acd
->userdata
);
155 int sd_ipv4acd_stop(sd_ipv4acd
*acd
) {
156 assert_return(acd
, -EINVAL
);
160 log_ipv4acd(acd
, "STOPPED");
162 ipv4acd_client_notify(acd
, SD_IPV4ACD_EVENT_STOP
);
167 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
);
169 static int ipv4acd_set_next_wakeup(sd_ipv4acd
*acd
, usec_t usec
, usec_t random_usec
) {
170 _cleanup_(sd_event_source_unrefp
) sd_event_source
*timer
= NULL
;
171 usec_t next_timeout
, time_now
;
179 next_timeout
+= (usec_t
) random_u64() % random_usec
;
181 assert_se(sd_event_now(acd
->event
, clock_boottime_or_monotonic(), &time_now
) >= 0);
183 r
= sd_event_add_time(acd
->event
, &timer
, clock_boottime_or_monotonic(), time_now
+ next_timeout
, 0, ipv4acd_on_timeout
, acd
);
187 r
= sd_event_source_set_priority(timer
, acd
->event_priority
);
191 (void) sd_event_source_set_description(timer
, "ipv4acd-timer");
193 sd_event_source_unref(acd
->timer_event_source
);
194 acd
->timer_event_source
= TAKE_PTR(timer
);
199 static bool ipv4acd_arp_conflict(sd_ipv4acd
*acd
, struct ether_arp
*arp
) {
204 if (memcmp(arp
->arp_spa
, &acd
->address
, sizeof(acd
->address
)) == 0)
207 /* the TPA matched instead of the SPA, this is not a conflict */
211 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
212 sd_ipv4acd
*acd
= userdata
;
217 switch (acd
->state
) {
219 case IPV4ACD_STATE_STARTED
:
220 ipv4acd_set_state(acd
, IPV4ACD_STATE_WAITING_PROBE
, true);
222 if (acd
->n_conflict
>= MAX_CONFLICTS
) {
223 char ts
[FORMAT_TIMESPAN_MAX
];
224 log_ipv4acd(acd
, "Max conflicts reached, delaying by %s", format_timespan(ts
, sizeof(ts
), RATE_LIMIT_INTERVAL_USEC
, 0));
226 r
= ipv4acd_set_next_wakeup(acd
, RATE_LIMIT_INTERVAL_USEC
, PROBE_WAIT_USEC
);
230 r
= ipv4acd_set_next_wakeup(acd
, 0, PROBE_WAIT_USEC
);
237 case IPV4ACD_STATE_WAITING_PROBE
:
238 case IPV4ACD_STATE_PROBING
:
240 r
= arp_send_probe(acd
->fd
, acd
->ifindex
, acd
->address
, &acd
->mac_addr
);
242 log_ipv4acd_errno(acd
, r
, "Failed to send ARP probe: %m");
245 _cleanup_free_
char *address
= NULL
;
246 union in_addr_union addr
= { .in
.s_addr
= acd
->address
};
248 (void) in_addr_to_string(AF_INET
, &addr
, &address
);
249 log_ipv4acd(acd
, "Probing %s", strna(address
));
252 if (acd
->n_iteration
< PROBE_NUM
- 2) {
253 ipv4acd_set_state(acd
, IPV4ACD_STATE_PROBING
, false);
255 r
= ipv4acd_set_next_wakeup(acd
, PROBE_MIN_USEC
, (PROBE_MAX_USEC
-PROBE_MIN_USEC
));
259 ipv4acd_set_state(acd
, IPV4ACD_STATE_WAITING_ANNOUNCE
, true);
261 r
= ipv4acd_set_next_wakeup(acd
, ANNOUNCE_WAIT_USEC
, 0);
268 case IPV4ACD_STATE_ANNOUNCING
:
269 if (acd
->n_iteration
>= ANNOUNCE_NUM
- 1) {
270 ipv4acd_set_state(acd
, IPV4ACD_STATE_RUNNING
, false);
275 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
276 /* Send announcement packet */
277 r
= arp_send_announcement(acd
->fd
, acd
->ifindex
, acd
->address
, &acd
->mac_addr
);
279 log_ipv4acd_errno(acd
, r
, "Failed to send ARP announcement: %m");
282 log_ipv4acd(acd
, "ANNOUNCE");
284 ipv4acd_set_state(acd
, IPV4ACD_STATE_ANNOUNCING
, false);
286 r
= ipv4acd_set_next_wakeup(acd
, ANNOUNCE_INTERVAL_USEC
, 0);
290 if (acd
->n_iteration
== 0) {
292 ipv4acd_client_notify(acd
, SD_IPV4ACD_EVENT_BIND
);
298 assert_not_reached("Invalid state.");
304 sd_ipv4acd_stop(acd
);
308 static void ipv4acd_on_conflict(sd_ipv4acd
*acd
) {
309 _cleanup_free_
char *address
= NULL
;
310 union in_addr_union addr
= { .in
.s_addr
= acd
->address
};
316 (void) in_addr_to_string(AF_INET
, &addr
, &address
);
317 log_ipv4acd(acd
, "Conflict on %s (%u)", strna(address
), acd
->n_conflict
);
320 ipv4acd_client_notify(acd
, SD_IPV4ACD_EVENT_CONFLICT
);
323 static int ipv4acd_on_packet(
329 sd_ipv4acd
*acd
= userdata
;
330 struct ether_arp packet
;
338 n
= recv(fd
, &packet
, sizeof(struct ether_arp
), 0);
340 if (IN_SET(errno
, EAGAIN
, EINTR
))
343 log_ipv4acd_errno(acd
, errno
, "Failed to read ARP packet: %m");
346 if ((size_t) n
!= sizeof(struct ether_arp
)) {
347 log_ipv4acd(acd
, "Ignoring too short ARP packet.");
351 switch (acd
->state
) {
353 case IPV4ACD_STATE_ANNOUNCING
:
354 case IPV4ACD_STATE_RUNNING
:
356 if (ipv4acd_arp_conflict(acd
, &packet
)) {
359 assert_se(sd_event_now(acd
->event
, clock_boottime_or_monotonic(), &ts
) >= 0);
362 if (ts
> acd
->defend_window
) {
363 acd
->defend_window
= ts
+ DEFEND_INTERVAL_USEC
;
364 r
= arp_send_announcement(acd
->fd
, acd
->ifindex
, acd
->address
, &acd
->mac_addr
);
366 log_ipv4acd_errno(acd
, r
, "Failed to send ARP announcement: %m");
369 log_ipv4acd(acd
, "DEFEND");
372 ipv4acd_on_conflict(acd
);
376 case IPV4ACD_STATE_WAITING_PROBE
:
377 case IPV4ACD_STATE_PROBING
:
378 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
379 /* BPF ensures this packet indicates a conflict */
380 ipv4acd_on_conflict(acd
);
384 assert_not_reached("Invalid state.");
390 sd_ipv4acd_stop(acd
);
394 int sd_ipv4acd_set_ifindex(sd_ipv4acd
*acd
, int ifindex
) {
395 assert_return(acd
, -EINVAL
);
396 assert_return(ifindex
> 0, -EINVAL
);
397 assert_return(acd
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
399 acd
->ifindex
= ifindex
;
404 int sd_ipv4acd_set_mac(sd_ipv4acd
*acd
, const struct ether_addr
*addr
) {
405 assert_return(acd
, -EINVAL
);
406 assert_return(addr
, -EINVAL
);
407 assert_return(acd
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
409 acd
->mac_addr
= *addr
;
414 int sd_ipv4acd_detach_event(sd_ipv4acd
*acd
) {
415 assert_return(acd
, -EINVAL
);
417 acd
->event
= sd_event_unref(acd
->event
);
422 int sd_ipv4acd_attach_event(sd_ipv4acd
*acd
, sd_event
*event
, int64_t priority
) {
425 assert_return(acd
, -EINVAL
);
426 assert_return(!acd
->event
, -EBUSY
);
429 acd
->event
= sd_event_ref(event
);
431 r
= sd_event_default(&acd
->event
);
436 acd
->event_priority
= priority
;
441 int sd_ipv4acd_set_callback(sd_ipv4acd
*acd
, sd_ipv4acd_callback_t cb
, void *userdata
) {
442 assert_return(acd
, -EINVAL
);
445 acd
->userdata
= userdata
;
450 int sd_ipv4acd_set_address(sd_ipv4acd
*acd
, const struct in_addr
*address
) {
451 assert_return(acd
, -EINVAL
);
452 assert_return(address
, -EINVAL
);
453 assert_return(acd
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
455 acd
->address
= address
->s_addr
;
460 int sd_ipv4acd_is_running(sd_ipv4acd
*acd
) {
461 assert_return(acd
, false);
463 return acd
->state
!= IPV4ACD_STATE_INIT
;
466 int sd_ipv4acd_start(sd_ipv4acd
*acd
) {
469 assert_return(acd
, -EINVAL
);
470 assert_return(acd
->event
, -EINVAL
);
471 assert_return(acd
->ifindex
> 0, -EINVAL
);
472 assert_return(acd
->address
!= 0, -EINVAL
);
473 assert_return(!ether_addr_is_null(&acd
->mac_addr
), -EINVAL
);
474 assert_return(acd
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
476 r
= arp_network_bind_raw_socket(acd
->ifindex
, acd
->address
, &acd
->mac_addr
);
482 acd
->defend_window
= 0;
485 r
= sd_event_add_io(acd
->event
, &acd
->receive_message_event_source
, acd
->fd
, EPOLLIN
, ipv4acd_on_packet
, acd
);
489 r
= sd_event_source_set_priority(acd
->receive_message_event_source
, acd
->event_priority
);
493 (void) sd_event_source_set_description(acd
->receive_message_event_source
, "ipv4acd-receive-message");
495 r
= ipv4acd_set_next_wakeup(acd
, 0, 0);
499 ipv4acd_set_state(acd
, IPV4ACD_STATE_STARTED
, true);