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"
39 /* Constants from the RFC */
44 #define ANNOUNCE_WAIT 2
45 #define ANNOUNCE_NUM 2
46 #define ANNOUNCE_INTERVAL 2
47 #define MAX_CONFLICTS 10
48 #define RATE_LIMIT_INTERVAL 60
49 #define DEFEND_INTERVAL 10
51 #define IPV4ACD_NETWORK 0xA9FE0000UL
52 #define IPV4ACD_NETMASK 0xFFFF0000UL
54 #define log_ipv4acd_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__)
55 #define log_ipv4acd(ll, fmt, ...) log_ipv4acd_errno(ll, 0, fmt, ##__VA_ARGS__)
57 typedef enum IPv4ACDState
{
59 IPV4ACD_STATE_WAITING_PROBE
,
60 IPV4ACD_STATE_PROBING
,
61 IPV4ACD_STATE_WAITING_ANNOUNCE
,
62 IPV4ACD_STATE_ANNOUNCING
,
63 IPV4ACD_STATE_RUNNING
,
65 _IPV4ACD_STATE_INVALID
= -1
78 sd_event_source
*receive_message
;
79 sd_event_source
*timer
;
85 struct ether_addr mac_addr
;
89 sd_ipv4acd_callback_t callback
;
93 sd_ipv4acd
*sd_ipv4acd_ref(sd_ipv4acd
*ll
) {
97 assert_se(ll
->n_ref
>= 1);
103 sd_ipv4acd
*sd_ipv4acd_unref(sd_ipv4acd
*ll
) {
107 assert_se(ll
->n_ref
>= 1);
113 ll
->receive_message
= sd_event_source_unref(ll
->receive_message
);
114 ll
->fd
= safe_close(ll
->fd
);
116 ll
->timer
= sd_event_source_unref(ll
->timer
);
118 sd_ipv4acd_detach_event(ll
);
125 int sd_ipv4acd_new(sd_ipv4acd
**ret
) {
126 _cleanup_(sd_ipv4acd_unrefp
) sd_ipv4acd
*ll
= NULL
;
128 assert_return(ret
, -EINVAL
);
130 ll
= new0(sd_ipv4acd
, 1);
135 ll
->state
= IPV4ACD_STATE_INIT
;
145 static void ipv4acd_set_state(sd_ipv4acd
*ll
, IPv4ACDState st
, bool reset_counter
) {
148 assert(st
< _IPV4ACD_STATE_MAX
);
150 if (st
== ll
->state
&& !reset_counter
)
158 static void ipv4acd_client_notify(sd_ipv4acd
*ll
, int event
) {
164 ll
->callback(ll
, event
, ll
->userdata
);
167 static void ipv4acd_stop(sd_ipv4acd
*ll
) {
170 ll
->receive_message
= sd_event_source_unref(ll
->receive_message
);
171 ll
->fd
= safe_close(ll
->fd
);
173 ll
->timer
= sd_event_source_unref(ll
->timer
);
175 log_ipv4acd(ll
, "STOPPED");
177 ipv4acd_set_state (ll
, IPV4ACD_STATE_INIT
, true);
180 int sd_ipv4acd_stop(sd_ipv4acd
*ll
) {
181 assert_return(ll
, -EINVAL
);
185 ipv4acd_client_notify(ll
, SD_IPV4ACD_EVENT_STOP
);
190 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
);
192 static int ipv4acd_set_next_wakeup(sd_ipv4acd
*ll
, int sec
, int random_sec
) {
193 _cleanup_(sd_event_source_unrefp
) sd_event_source
*timer
= NULL
;
199 assert(random_sec
>= 0);
202 next_timeout
= sec
* USEC_PER_SEC
;
205 next_timeout
+= random_u32() % (random_sec
* USEC_PER_SEC
);
207 assert_se(sd_event_now(ll
->event
, clock_boottime_or_monotonic(), &time_now
) >= 0);
209 r
= sd_event_add_time(ll
->event
, &timer
, clock_boottime_or_monotonic(),
210 time_now
+ next_timeout
, 0, ipv4acd_on_timeout
, ll
);
214 r
= sd_event_source_set_priority(timer
, ll
->event_priority
);
218 r
= sd_event_source_set_description(timer
, "ipv4acd-timer");
222 ll
->timer
= sd_event_source_unref(ll
->timer
);
229 static bool ipv4acd_arp_conflict(sd_ipv4acd
*ll
, struct ether_arp
*arp
) {
234 if (memcmp(arp
->arp_spa
, &ll
->address
, sizeof(ll
->address
)) == 0)
237 /* the TPA matched instead of the SPA, this is not a conflict */
241 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
242 sd_ipv4acd
*ll
= userdata
;
248 case IPV4ACD_STATE_INIT
:
250 ipv4acd_set_state(ll
, IPV4ACD_STATE_WAITING_PROBE
, true);
252 if (ll
->n_conflict
>= MAX_CONFLICTS
) {
253 log_ipv4acd(ll
, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL
);
255 r
= ipv4acd_set_next_wakeup(ll
, RATE_LIMIT_INTERVAL
, PROBE_WAIT
);
261 r
= ipv4acd_set_next_wakeup(ll
, 0, PROBE_WAIT
);
267 case IPV4ACD_STATE_WAITING_PROBE
:
268 case IPV4ACD_STATE_PROBING
:
270 r
= arp_send_probe(ll
->fd
, ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
272 log_ipv4acd_errno(ll
, r
, "Failed to send ARP probe: %m");
275 _cleanup_free_
char *address
= NULL
;
276 union in_addr_union addr
= { .in
.s_addr
= ll
->address
};
278 r
= in_addr_to_string(AF_INET
, &addr
, &address
);
280 log_ipv4acd(ll
, "Probing %s", address
);
283 if (ll
->n_iteration
< PROBE_NUM
- 2) {
284 ipv4acd_set_state(ll
, IPV4ACD_STATE_PROBING
, false);
286 r
= ipv4acd_set_next_wakeup(ll
, PROBE_MIN
, (PROBE_MAX
-PROBE_MIN
));
290 ipv4acd_set_state(ll
, IPV4ACD_STATE_WAITING_ANNOUNCE
, true);
292 r
= ipv4acd_set_next_wakeup(ll
, ANNOUNCE_WAIT
, 0);
299 case IPV4ACD_STATE_ANNOUNCING
:
300 if (ll
->n_iteration
>= ANNOUNCE_NUM
- 1) {
301 ipv4acd_set_state(ll
, IPV4ACD_STATE_RUNNING
, false);
305 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
306 /* Send announcement packet */
307 r
= arp_send_announcement(ll
->fd
, ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
309 log_ipv4acd_errno(ll
, r
, "Failed to send ARP announcement: %m");
312 log_ipv4acd(ll
, "ANNOUNCE");
314 ipv4acd_set_state(ll
, IPV4ACD_STATE_ANNOUNCING
, false);
316 r
= ipv4acd_set_next_wakeup(ll
, ANNOUNCE_INTERVAL
, 0);
320 if (ll
->n_iteration
== 0) {
322 ipv4acd_client_notify(ll
, SD_IPV4ACD_EVENT_BIND
);
327 assert_not_reached("Invalid state.");
337 static void ipv4acd_on_conflict(sd_ipv4acd
*ll
) {
338 _cleanup_free_
char *address
= NULL
;
339 union in_addr_union addr
= { .in
.s_addr
= ll
->address
};
346 r
= in_addr_to_string(AF_INET
, &addr
, &address
);
348 log_ipv4acd(ll
, "Conflict on %s (%u)", address
, ll
->n_conflict
);
352 ipv4acd_client_notify(ll
, SD_IPV4ACD_EVENT_CONFLICT
);
355 static int ipv4acd_on_packet(
361 sd_ipv4acd
*ll
= userdata
;
362 struct ether_arp packet
;
370 n
= recv(fd
, &packet
, sizeof(struct ether_arp
), 0);
372 if (errno
== EAGAIN
|| errno
== EINTR
)
375 r
= log_ipv4acd_errno(ll
, errno
, "Failed to read ARP packet: %m");
378 if ((size_t) n
!= sizeof(struct ether_arp
)) {
379 log_ipv4acd(ll
, "Ignoring too short ARP packet.");
385 case IPV4ACD_STATE_ANNOUNCING
:
386 case IPV4ACD_STATE_RUNNING
:
388 if (ipv4acd_arp_conflict(ll
, &packet
)) {
391 assert_se(sd_event_now(ll
->event
, clock_boottime_or_monotonic(), &ts
) >= 0);
394 if (ts
> ll
->defend_window
) {
395 ll
->defend_window
= ts
+ DEFEND_INTERVAL
* USEC_PER_SEC
;
396 r
= arp_send_announcement(ll
->fd
, ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
398 log_ipv4acd_errno(ll
, r
, "Failed to send ARP announcement: %m");
401 log_ipv4acd(ll
, "DEFEND");
404 ipv4acd_on_conflict(ll
);
408 case IPV4ACD_STATE_WAITING_PROBE
:
409 case IPV4ACD_STATE_PROBING
:
410 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
411 /* BPF ensures this packet indicates a conflict */
412 ipv4acd_on_conflict(ll
);
416 assert_not_reached("Invalid state.");
426 int sd_ipv4acd_set_ifindex(sd_ipv4acd
*ll
, int ifindex
) {
427 assert_return(ll
, -EINVAL
);
428 assert_return(ifindex
> 0, -EINVAL
);
429 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
431 ll
->ifindex
= ifindex
;
436 int sd_ipv4acd_set_mac(sd_ipv4acd
*ll
, const struct ether_addr
*addr
) {
437 assert_return(ll
, -EINVAL
);
438 assert_return(addr
, -EINVAL
);
439 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
441 memcpy(&ll
->mac_addr
, addr
, ETH_ALEN
);
446 int sd_ipv4acd_detach_event(sd_ipv4acd
*ll
) {
447 assert_return(ll
, -EINVAL
);
449 ll
->event
= sd_event_unref(ll
->event
);
454 int sd_ipv4acd_attach_event(sd_ipv4acd
*ll
, sd_event
*event
, int64_t priority
) {
457 assert_return(ll
, -EINVAL
);
458 assert_return(!ll
->event
, -EBUSY
);
461 ll
->event
= sd_event_ref(event
);
463 r
= sd_event_default(&ll
->event
);
468 ll
->event_priority
= priority
;
473 int sd_ipv4acd_set_callback(sd_ipv4acd
*ll
, sd_ipv4acd_callback_t cb
, void *userdata
) {
474 assert_return(ll
, -EINVAL
);
477 ll
->userdata
= userdata
;
482 int sd_ipv4acd_set_address(sd_ipv4acd
*ll
, const struct in_addr
*address
) {
483 assert_return(ll
, -EINVAL
);
484 assert_return(address
, -EINVAL
);
485 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
487 ll
->address
= address
->s_addr
;
492 int sd_ipv4acd_is_running(sd_ipv4acd
*ll
) {
493 assert_return(ll
, false);
495 return ll
->state
!= IPV4ACD_STATE_INIT
;
498 int sd_ipv4acd_start(sd_ipv4acd
*ll
) {
501 assert_return(ll
, -EINVAL
);
502 assert_return(ll
->event
, -EINVAL
);
503 assert_return(ll
->ifindex
> 0, -EINVAL
);
504 assert_return(ll
->address
!= 0, -EINVAL
);
505 assert_return(!ether_addr_is_null(&ll
->mac_addr
), -EINVAL
);
506 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
508 ll
->defend_window
= 0;
510 r
= arp_network_bind_raw_socket(ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
514 ll
->fd
= safe_close(ll
->fd
);
517 r
= sd_event_add_io(ll
->event
, &ll
->receive_message
, ll
->fd
,
518 EPOLLIN
, ipv4acd_on_packet
, ll
);
522 r
= sd_event_source_set_priority(ll
->receive_message
, ll
->event_priority
);
526 r
= sd_event_source_set_description(ll
->receive_message
, "ipv4acd-receive-message");
530 r
= ipv4acd_set_next_wakeup(ll
, 0, 0);