2 This file is part of systemd.
4 Copyright (C) 2014 Axis Communications AB. All rights reserved.
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.
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.
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/>.
24 #include <arpa/inet.h>
29 #include "ipv4ll-internal.h"
30 #include "sd-ipv4ll.h"
32 /* Constants from the RFC */
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
44 #define IPV4LL_NETWORK 0xA9FE0000L
45 #define IPV4LL_NETMASK 0xFFFF0000L
47 typedef enum IPv4LLTrigger
{
49 IPV4LL_TRIGGER_PACKET
,
50 IPV4LL_TRIGGER_TIMEOUT
,
52 _IPV4LL_TRIGGER_INVALID
= -1
55 typedef enum IPv4LLState
{
57 IPV4LL_STATE_WAITING_PROBE
,
59 IPV4LL_STATE_WAITING_ANNOUNCE
,
60 IPV4LL_STATE_ANNOUNCING
,
63 _IPV4LL_STATE_INVALID
= -1
70 union sockaddr_union link
;
73 sd_event_source
*receive_message
;
74 sd_event_source
*timer
;
77 int next_wakeup_valid
;
80 be32_t claimed_address
;
81 struct ether_addr mac_addr
;
88 static void ipv4ll_run_state_machine(sd_ipv4ll
*ll
, IPv4LLTrigger trigger
, void *trigger_data
);
90 static void ipv4ll_set_state(sd_ipv4ll
*ll
, IPv4LLState st
, int reset_counter
) {
93 assert(st
< _IPV4LL_STATE_MAX
);
95 if (st
== ll
->state
&& !reset_counter
) {
103 static int ipv4ll_client_notify(sd_ipv4ll
*ll
, int event
) {
107 ll
->cb(ll
, event
, ll
->userdata
);
112 static int ipv4ll_stop(sd_ipv4ll
*ll
, int event
) {
115 ll
->receive_message
= sd_event_source_unref(ll
->receive_message
);
117 close_nointr_nofail(ll
->fd
);
120 ll
->timer
= sd_event_source_unref(ll
->timer
);
122 ipv4ll_client_notify(ll
, event
);
124 ll
->claimed_address
= 0;
126 ipv4ll_set_state (ll
, IPV4LL_STATE_INIT
, 1);
128 log_ipv4ll(ll
, "STOPPED");
133 static be32_t
ipv4ll_pick_address(sd_ipv4ll
*ll
) {
140 uint32_t r
= random_u32() & 0x0000FFFF;
141 addr
= htonl(IPV4LL_NETWORK
| r
);
142 } while (addr
== ll
->address
||
143 (ntohl(addr
) & IPV4LL_NETMASK
) != IPV4LL_NETWORK
||
144 (ntohl(addr
) & 0x0000FF00) == 0x0000 ||
145 (ntohl(addr
) & 0x0000FF00) == 0xFF00);
150 for (i
= 0; i
< ETH_ALEN
; i
++)
151 a
+= ll
->mac_addr
.ether_addr_octet
[i
]*i
;
152 a
= (a
% 0xFE00) + 0x0100;
153 addr
= htonl(IPV4LL_NETWORK
| (uint32_t) a
);
159 static int ipv4ll_timer(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
160 sd_ipv4ll
*ll
= (sd_ipv4ll
*)userdata
;
164 ll
->next_wakeup_valid
= 0;
165 ipv4ll_run_state_machine(ll
, IPV4LL_TRIGGER_TIMEOUT
, NULL
);
170 static void ipv4ll_set_next_wakeup (sd_ipv4ll
*ll
, int sec
, int random_sec
) {
171 usec_t next_timeout
= 0;
175 assert(random_sec
>= 0);
178 next_timeout
= sec
* USEC_PER_SEC
;
181 next_timeout
+= random_u32() % (random_sec
* USEC_PER_SEC
);
183 if (sd_event_get_now_monotonic(ll
->event
, &time_now
) < 0)
184 time_now
= now(CLOCK_MONOTONIC
);
186 ll
->next_wakeup
= time_now
+ next_timeout
;
187 ll
->next_wakeup_valid
= 1;
190 static bool ipv4ll_arp_conflict (sd_ipv4ll
*ll
, struct ether_arp
*arp
) {
194 if (memcmp(arp
->arp_spa
, &ll
->address
, sizeof(ll
->address
)) == 0 &&
195 memcmp(arp
->arp_sha
, &ll
->mac_addr
, ETH_ALEN
) != 0)
201 static bool ipv4ll_arp_probe_conflict (sd_ipv4ll
*ll
, struct ether_arp
*arp
) {
205 if (ipv4ll_arp_conflict(ll
, arp
))
208 if (memcmp(arp
->arp_tpa
, &ll
->address
, sizeof(ll
->address
)) == 0 &&
209 memcmp(arp
->arp_sha
, &ll
->mac_addr
, ETH_ALEN
))
215 static void ipv4ll_run_state_machine(sd_ipv4ll
*ll
, IPv4LLTrigger trigger
, void *trigger_data
) {
216 struct ether_arp out_packet
;
217 int out_packet_ready
= 0;
221 assert(trigger
< _IPV4LL_TRIGGER_MAX
);
223 if (ll
->state
== IPV4LL_STATE_INIT
) {
225 log_ipv4ll(ll
, "PROBE");
226 ipv4ll_set_state(ll
, IPV4LL_STATE_WAITING_PROBE
, 1);
227 ipv4ll_set_next_wakeup(ll
, 0, PROBE_WAIT
);
229 } else if ((ll
->state
== IPV4LL_STATE_WAITING_PROBE
&& trigger
== IPV4LL_TRIGGER_TIMEOUT
) ||
230 (ll
->state
== IPV4LL_STATE_PROBING
&& trigger
== IPV4LL_TRIGGER_TIMEOUT
&& ll
->iteration
< PROBE_NUM
-2)) {
233 arp_packet_probe(&out_packet
, ll
->address
, &ll
->mac_addr
);
234 out_packet_ready
= 1;
235 ipv4ll_set_state(ll
, IPV4LL_STATE_PROBING
, 0);
237 ipv4ll_set_next_wakeup(ll
, PROBE_MIN
, (PROBE_MAX
-PROBE_MIN
));
239 } else if (ll
->state
== IPV4LL_STATE_PROBING
&& trigger
== IPV4LL_TRIGGER_TIMEOUT
&& ll
->iteration
>= PROBE_NUM
-2) {
241 /* Send the last probe */
242 arp_packet_probe(&out_packet
, ll
->address
, &ll
->mac_addr
);
243 out_packet_ready
= 1;
244 ipv4ll_set_state(ll
, IPV4LL_STATE_WAITING_ANNOUNCE
, 1);
246 ipv4ll_set_next_wakeup(ll
, ANNOUNCE_WAIT
, 0);
248 } else if ((ll
->state
== IPV4LL_STATE_WAITING_ANNOUNCE
&& trigger
== IPV4LL_TRIGGER_TIMEOUT
) ||
249 (ll
->state
== IPV4LL_STATE_ANNOUNCING
&& trigger
== IPV4LL_TRIGGER_TIMEOUT
&& ll
->iteration
< ANNOUNCE_NUM
-1)) {
251 /* Send announcement packet */
252 arp_packet_announcement(&out_packet
, ll
->address
, &ll
->mac_addr
);
253 out_packet_ready
= 1;
254 ipv4ll_set_state(ll
, IPV4LL_STATE_ANNOUNCING
, 0);
256 ipv4ll_set_next_wakeup(ll
, ANNOUNCE_INTERVAL
, 0);
258 if (ll
->iteration
== 0) {
259 log_ipv4ll(ll
, "ANNOUNCE");
260 ll
->claimed_address
= ll
->address
;
261 r
= ipv4ll_client_notify(ll
, IPV4LL_EVENT_BIND
);
265 } else if ((ll
->state
== IPV4LL_STATE_ANNOUNCING
&& trigger
== IPV4LL_TRIGGER_TIMEOUT
&&
266 ll
->iteration
>= ANNOUNCE_NUM
-1)) {
268 ipv4ll_set_state(ll
, IPV4LL_STATE_RUNNING
, 0);
269 ll
->next_wakeup_valid
= 0;
271 } else if (trigger
== IPV4LL_TRIGGER_PACKET
) {
275 struct ether_arp
* in_packet
= (struct ether_arp
*)trigger_data
;
279 if (IN_SET(ll
->state
, IPV4LL_STATE_ANNOUNCING
, IPV4LL_STATE_RUNNING
)) {
281 if (ipv4ll_arp_conflict(ll
, in_packet
)) {
283 r
= sd_event_get_now_monotonic(ll
->event
, &time_now
);
288 if (time_now
> ll
->defend_window
) {
289 ll
->defend_window
= time_now
+ DEFEND_INTERVAL
* USEC_PER_SEC
;
290 arp_packet_announcement(&out_packet
, ll
->address
, &ll
->mac_addr
);
291 out_packet_ready
= 1;
296 } else if (IN_SET(ll
->state
, IPV4LL_STATE_WAITING_PROBE
,
297 IPV4LL_STATE_PROBING
,
298 IPV4LL_STATE_WAITING_ANNOUNCE
)) {
300 conflicted
= ipv4ll_arp_probe_conflict(ll
, in_packet
);
304 log_ipv4ll(ll
, "CONFLICT");
305 r
= ipv4ll_client_notify(ll
, IPV4LL_EVENT_CONFLICT
);
306 ll
->claimed_address
= 0;
308 /* Pick a new address */
309 ll
->address
= ipv4ll_pick_address(ll
);
311 ll
->defend_window
= 0;
312 ipv4ll_set_state(ll
, IPV4LL_STATE_WAITING_PROBE
, 1);
314 if (ll
->conflict
>= MAX_CONFLICTS
) {
315 log_ipv4ll(ll
, "MAX_CONFLICTS");
316 ipv4ll_set_next_wakeup(ll
, RATE_LIMIT_INTERVAL
, PROBE_WAIT
);
318 ipv4ll_set_next_wakeup(ll
, 0, PROBE_WAIT
);
323 if (out_packet_ready
) {
324 r
= arp_network_send_raw_socket(ll
->fd
, &ll
->link
, &out_packet
);
326 log_ipv4ll(ll
, "failed to send arp packet out");
331 if (ll
->next_wakeup_valid
) {
332 ll
->timer
= sd_event_source_unref(ll
->timer
);
333 r
= sd_event_add_monotonic(ll
->event
, &ll
->timer
,
334 ll
->next_wakeup
, 0, ipv4ll_timer
, ll
);
338 r
= sd_event_source_set_priority(ll
->timer
, ll
->event_priority
);
348 static int ipv4ll_receive_message(sd_event_source
*s
, int fd
,
349 uint32_t revents
, void *userdata
) {
351 struct ether_arp arp
;
352 sd_ipv4ll
*ll
= (sd_ipv4ll
*)userdata
;
356 r
= read(fd
, &arp
, sizeof(struct ether_arp
));
357 if (r
< (int) sizeof(struct ether_arp
))
360 r
= arp_packet_verify_headers(&arp
);
364 ipv4ll_run_state_machine(ll
, IPV4LL_TRIGGER_PACKET
, &arp
);
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
);
374 ll
->index
= interface_index
;
379 int sd_ipv4ll_set_mac(sd_ipv4ll
*ll
, const struct ether_addr
*addr
) {
380 assert_return(ll
, -EINVAL
);
381 assert_return(ll
->state
== IPV4LL_STATE_INIT
, -EBUSY
);
383 memcpy(&ll
->mac_addr
.ether_addr_octet
, addr
, ETH_ALEN
);
388 int sd_ipv4ll_detach_event(sd_ipv4ll
*ll
) {
389 assert_return(ll
, -EINVAL
);
391 ll
->event
= sd_event_unref(ll
->event
);
396 int sd_ipv4ll_attach_event(sd_ipv4ll
*ll
, sd_event
*event
, int priority
) {
399 assert_return(ll
, -EINVAL
);
400 assert_return(!ll
->event
, -EBUSY
);
403 ll
->event
= sd_event_ref(event
);
405 r
= sd_event_default(&ll
->event
);
407 ipv4ll_stop(ll
, IPV4LL_EVENT_STOP
);
412 ll
->event_priority
= priority
;
417 int sd_ipv4ll_set_callback(sd_ipv4ll
*ll
, sd_ipv4ll_cb_t cb
, void *userdata
) {
418 assert_return(ll
, -EINVAL
);
421 ll
->userdata
= userdata
;
426 int sd_ipv4ll_get_address(sd_ipv4ll
*ll
, struct in_addr
*address
){
427 assert_return(ll
, -EINVAL
);
428 assert_return(address
, -EINVAL
);
430 if (ll
->claimed_address
== 0) {
434 address
->s_addr
= ll
->claimed_address
;
438 int sd_ipv4ll_start (sd_ipv4ll
*ll
) {
441 assert_return(ll
, -EINVAL
);
442 assert_return(ll
->event
, -EINVAL
);
443 assert_return(ll
->index
> 0, -EINVAL
);
444 assert_return(ll
->state
== IPV4LL_STATE_INIT
, -EBUSY
);
446 r
= arp_network_bind_raw_socket(ll
->index
, &ll
->link
);
453 ll
->defend_window
= 0;
454 ll
->claimed_address
= 0;
456 if (ll
->address
== 0)
457 ll
->address
= ipv4ll_pick_address(ll
);
459 ipv4ll_set_state (ll
, IPV4LL_STATE_INIT
, 1);
461 r
= sd_event_add_io(ll
->event
, &ll
->receive_message
, ll
->fd
,
462 EPOLLIN
, ipv4ll_receive_message
, ll
);
466 r
= sd_event_source_set_priority(ll
->receive_message
, ll
->event_priority
);
470 r
= sd_event_add_monotonic(ll
->event
, &ll
->timer
, now(CLOCK_MONOTONIC
), 0,
476 r
= sd_event_source_set_priority(ll
->timer
, ll
->event_priority
);
480 ipv4ll_stop(ll
, IPV4LL_EVENT_STOP
);
485 int sd_ipv4ll_stop(sd_ipv4ll
*ll
) {
486 return ipv4ll_stop(ll
, IPV4LL_EVENT_STOP
);
489 void sd_ipv4ll_free (sd_ipv4ll
*ll
) {
494 sd_ipv4ll_detach_event(ll
);
499 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll
*, sd_ipv4ll_free
);
500 #define _cleanup_ipv4ll_free_ _cleanup_(sd_ipv4ll_freep)
502 int sd_ipv4ll_new(sd_ipv4ll
**ret
) {
503 _cleanup_ipv4ll_free_ sd_ipv4ll
*ll
= NULL
;
505 assert_return(ret
, -EINVAL
);
507 ll
= new0(sd_ipv4ll
, 1);
511 ll
->state
= IPV4LL_STATE_INIT
;