5 * Copyright (C) 2018 Commend International GmbH. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
19 * Address Conflict Detection (RFC 5227)
21 * based on DHCP client library with GLib integration,
22 * Copyright (C) 2009-2014 Intel Corporation. All rights reserved.
26 #include <netinet/if_ether.h>
27 #include <net/if_arp.h>
35 #include <connman/acd.h>
36 #include <connman/log.h>
37 #include <connman/inet.h>
38 #include <connman/dbus.h>
40 #include "src/shared/arp.h"
49 static const char* acd_state_texts[] = {
60 uint8_t mac_address[6];
61 uint32_t requested_ip; /* host byte order */
63 /* address conflict fields */
64 uint32_t ac_ip; /* host byte order */
72 unsigned int retry_times;
73 unsigned int conflicts;
77 acd_host_cb_t ipv4_available_cb;
78 gpointer ipv4_available_data;
79 acd_host_cb_t ipv4_lost_cb;
80 gpointer ipv4_lost_data;
81 acd_host_cb_t ipv4_conflict_cb;
82 gpointer ipv4_conflict_data;
83 acd_host_cb_t ipv4_max_conflicts_cb;
84 gpointer ipv4_max_conflicts_data;
87 static int start_listening(struct acd_host *acd);
88 static void stop_listening(struct acd_host *acd);
89 static gboolean acd_listener_event(GIOChannel *channel, GIOCondition condition,
91 static int acd_recv_arp_packet(struct acd_host *acd);
92 static void send_probe_packet(gpointer acd_data);
93 static gboolean acd_probe_timeout(gpointer acd_data);
94 static gboolean send_announce_packet(gpointer acd_data);
95 static gboolean acd_announce_timeout(gpointer acd_data);
96 static gboolean acd_defend_timeout(gpointer acd_data);
98 /* for D-Bus property */
99 static void report_conflict(struct acd_host *acd, const struct ether_arp* arp);
101 static void debug(struct acd_host *acd, const char *format, ...)
106 va_start(ap, format);
108 if (vsnprintf(str, sizeof(str), format, ap) > 0)
109 connman_info("ACD index %d: %s", acd->ifindex, str);
114 void acd_host_free(struct acd_host *acd)
119 g_free(acd->interface);
123 struct acd_host *acd_host_new(int ifindex, const char *path)
125 struct acd_host *acd;
128 connman_error("Invalid interface index %d", ifindex);
132 acd = g_try_new0(struct acd_host, 1);
134 connman_error("Could not allocate ACD data structure");
138 acd->interface = connman_inet_ifname(ifindex);
139 if (!acd->interface) {
140 connman_error("Interface with index %d is not available", ifindex);
144 if (!connman_inet_is_ifup(ifindex)) {
145 connman_error("Interface with index %d and name %s is down", ifindex,
150 __connman_inet_get_interface_mac_address(ifindex, acd->mac_address);
152 acd->listener_sockfd = -1;
153 acd->listen_on = false;
154 acd->ifindex = ifindex;
155 acd->listener_watch = 0;
156 acd->retry_times = 0;
158 acd->ipv4_available_cb = NULL;
159 acd->ipv4_lost_cb = NULL;
160 acd->ipv4_conflict_cb = NULL;
161 acd->ipv4_max_conflicts_cb = NULL;
164 memset(acd->ac_mac, 0, sizeof(acd->ac_mac));
165 acd->ac_timestamp = 0;
166 acd->ac_resolved = true;
176 static void remove_timeout(struct acd_host *acd)
178 if (acd->timeout > 0)
179 g_source_remove(acd->timeout);
184 static int start_listening(struct acd_host *acd)
186 GIOChannel *listener_channel;
192 debug(acd, "start listening");
194 listener_sockfd = arp_socket(acd->ifindex);
195 if (listener_sockfd < 0)
198 listener_channel = g_io_channel_unix_new(listener_sockfd);
199 if (!listener_channel) {
200 /* Failed to create listener channel */
201 close(listener_sockfd);
205 acd->listen_on = true;
206 acd->listener_sockfd = listener_sockfd;
208 g_io_channel_set_close_on_unref(listener_channel, TRUE);
209 acd->listener_watch =
210 g_io_add_watch_full(listener_channel, G_PRIORITY_HIGH,
211 G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
212 acd_listener_event, acd,
214 g_io_channel_unref(listener_channel);
219 static void stop_listening(struct acd_host *acd)
224 if (acd->listener_watch > 0)
225 g_source_remove(acd->listener_watch);
226 acd->listen_on = FALSE;
227 acd->listener_sockfd = -1;
228 acd->listener_watch = 0;
231 static gboolean acd_listener_event(GIOChannel *channel, GIOCondition condition,
234 struct acd_host *acd = acd_data;
236 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
237 acd->listener_watch = 0;
244 acd_recv_arp_packet(acd);
249 static bool is_link_local(uint32_t ip)
251 return (ip & LINKLOCAL_ADDR) == LINKLOCAL_ADDR;
254 static int acd_recv_arp_packet(struct acd_host *acd)
257 struct ether_arp arp;
258 uint32_t ip_n; /* network byte order */
267 memset(&arp, 0, sizeof(arp));
268 cnt = read(acd->listener_sockfd, &arp, sizeof(arp));
269 if (cnt != sizeof(arp))
272 if (arp.arp_op != htons(ARPOP_REPLY) &&
273 arp.arp_op != htons(ARPOP_REQUEST))
276 if (memcmp(arp.arp_sha, acd->mac_address, ETH_ALEN) == 0)
279 ip_n = htonl(acd->requested_ip);
280 source_conflict = !memcmp(arp.arp_spa, &ip_n, sizeof(uint32_t));
281 probe = !memcmp(arp.arp_spa, "\0\0\0\0", sizeof(uint32_t));
282 target_conflict = probe &&
283 !memcmp(arp.arp_tpa, &ip_n, sizeof(uint32_t));
285 if (!source_conflict && !target_conflict)
290 confltxt = target_conflict ? "target" : "source";
293 debug(acd, "IPv4 %d %s conflicts detected for address %s. "
294 "State=%s", acd->conflicts, confltxt, inet_ntoa(addr),
295 acd_state_texts[acd->state]);
296 mac = acd->mac_address;
298 debug(acd, "Our MAC: %02x:%02x:%02x:%02x:%02x:%02x"
299 " other MAC: %02x:%02x:%02x:%02x:%02x:%02x",
300 mac[0], mac[1], mac[2],mac[3], mac[4], mac[5],
301 omac[0], omac[1], omac[2],omac[3], omac[4], omac[5]);
303 if (acd->state == ACD_STATE_MONITOR) {
304 if (!source_conflict)
307 acd->state = ACD_STATE_DEFEND;
308 debug(acd, "DEFEND mode conflicts: %d", acd->conflicts);
309 /* Try to defend with a single announce. */
310 send_announce_packet(acd);
312 } else if (acd->state == ACD_STATE_DEFEND) {
313 if (!source_conflict)
316 debug(acd, "LOST IPv4 address %s", inet_ntoa(addr));
317 if (!is_link_local(acd->requested_ip))
318 report_conflict(acd, &arp);
320 if (acd->ipv4_lost_cb)
321 acd->ipv4_lost_cb(acd, acd->ipv4_lost_data);
325 if (acd->conflicts < MAX_CONFLICTS) {
326 if (!is_link_local(acd->requested_ip))
327 report_conflict(acd, &arp);
331 /* we need a new request_ip */
332 if (acd->ipv4_conflict_cb)
333 acd->ipv4_conflict_cb(acd, acd->ipv4_conflict_data);
338 * Here we got a lot of conflicts, RFC3927 and RFC5227 state that we
339 * have to wait RATE_LIMIT_INTERVAL before retrying.
341 if (acd->ipv4_max_conflicts_cb)
342 acd->ipv4_max_conflicts_cb(acd, acd->ipv4_max_conflicts_data);
348 int acd_host_start(struct acd_host *acd, uint32_t ip)
355 err = start_listening(acd);
359 acd->retry_times = 0;
360 acd->requested_ip = ip;
362 /* First wait a random delay to avoid storm of ARP requests on boot */
363 timeout = __connman_util_random_delay_ms(PROBE_WAIT);
364 acd->state = ACD_STATE_PROBE;
366 acd->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
375 void acd_host_stop(struct acd_host *acd)
381 if (acd->listener_watch > 0) {
382 g_source_remove(acd->listener_watch);
383 acd->listener_watch = 0;
386 acd->state = ACD_STATE_PROBE;
387 acd->retry_times = 0;
388 acd->requested_ip = 0;
391 static void send_probe_packet(gpointer acd_data)
394 struct acd_host *acd = acd_data;
396 debug(acd, "sending ARP probe request");
398 if (acd->retry_times == 1) {
399 acd->state = ACD_STATE_PROBE;
400 start_listening(acd);
402 arp_send_packet(acd->mac_address, 0,
403 acd->requested_ip, acd->ifindex);
405 if (acd->retry_times < PROBE_NUM) {
406 /* Add a random timeout in range of PROBE_MIN to PROBE_MAX. */
407 timeout = __connman_util_random_delay_ms(PROBE_MAX-PROBE_MIN);
408 timeout += PROBE_MIN * 1000;
410 timeout = ANNOUNCE_WAIT * 1000;
412 acd->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
419 static gboolean acd_probe_timeout(gpointer acd_data)
421 struct acd_host *acd = acd_data;
425 debug(acd, "acd probe timeout (retries %d)", acd->retry_times);
426 if (acd->retry_times == PROBE_NUM) {
427 acd->state = ACD_STATE_ANNOUNCE;
428 acd->retry_times = 1;
430 send_announce_packet(acd);
435 send_probe_packet(acd);
440 static gboolean send_announce_packet(gpointer acd_data)
442 struct acd_host *acd = acd_data;
444 debug(acd, "sending ACD announce request");
446 arp_send_packet(acd->mac_address,
453 if (acd->state == ACD_STATE_DEFEND)
454 acd->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
460 acd->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
462 acd_announce_timeout,
468 static gboolean acd_announce_timeout(gpointer acd_data)
470 struct acd_host *acd = acd_data;
474 debug(acd, "acd announce timeout (retries %d)", acd->retry_times);
475 if (acd->retry_times != ANNOUNCE_NUM) {
477 send_announce_packet(acd);
481 debug(acd, "switching to monitor mode");
482 acd->state = ACD_STATE_MONITOR;
484 if (!acd->ac_resolved && !is_link_local(acd->requested_ip))
485 report_conflict(acd, NULL);
487 if (acd->ipv4_available_cb)
488 acd->ipv4_available_cb(acd,
489 acd->ipv4_available_data);
495 static gboolean acd_defend_timeout(gpointer acd_data)
497 struct acd_host *acd = acd_data;
499 debug(acd, "back to MONITOR mode");
502 acd->state = ACD_STATE_MONITOR;
507 void acd_host_register_event(struct acd_host *acd,
508 enum acd_host_event event,
513 case ACD_HOST_EVENT_IPV4_AVAILABLE:
514 acd->ipv4_available_cb = func;
515 acd->ipv4_available_data = user_data;
517 case ACD_HOST_EVENT_IPV4_LOST:
518 acd->ipv4_lost_cb = func;
519 acd->ipv4_lost_data = user_data;
521 case ACD_HOST_EVENT_IPV4_CONFLICT:
522 acd->ipv4_conflict_cb = func;
523 acd->ipv4_conflict_data = user_data;
525 case ACD_HOST_EVENT_IPV4_MAXCONFLICT:
526 acd->ipv4_max_conflicts_cb = func;
527 acd->ipv4_max_conflicts_data = user_data;
530 connman_warn("%s unknown event %d.", __FUNCTION__, event);
535 static void append_ac_mac(DBusMessageIter *iter, void *user_data)
537 struct acd_host *acd = user_data;
539 uint8_t *m = acd->ac_mac;
540 const char *str = mac;
542 snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
543 m[0], m[1], m[2], m[3], m[4], m[5]);
544 connman_dbus_dict_append_basic(iter, "Address", DBUS_TYPE_STRING, &str);
547 static void append_ac_ipv4(DBusMessageIter *iter, void *user_data)
549 struct acd_host *acd = user_data;
553 addr.s_addr = htonl(acd->ac_ip);
557 connman_dbus_dict_append_basic(iter, "Address", DBUS_TYPE_STRING, &a);
560 static void append_ac_property(DBusMessageIter *iter, void *user_data)
562 struct acd_host *acd = user_data;
564 connman_dbus_dict_append_dict(iter, "IPv4", append_ac_ipv4, acd);
565 connman_dbus_dict_append_dict(iter, "Ethernet", append_ac_mac, acd);
566 connman_dbus_dict_append_basic(iter, "Timestamp", DBUS_TYPE_INT64,
568 connman_dbus_dict_append_basic(iter, "Resolved", DBUS_TYPE_BOOLEAN,
572 void acd_host_append_dbus_property(struct acd_host *acd, DBusMessageIter *dict)
574 connman_dbus_dict_append_dict(dict, "LastAddressConflict",
575 append_ac_property, acd);
578 static void report_conflict(struct acd_host *acd, const struct ether_arp* arp)
581 acd->ac_ip = acd->requested_ip;
582 memcpy(acd->ac_mac, arp->arp_sha, sizeof(acd->ac_mac));
583 acd->ac_timestamp = g_get_real_time();
584 acd->ac_resolved = false;
586 acd->ac_resolved = true;
589 connman_dbus_property_changed_dict(acd->path, CONNMAN_SERVICE_INTERFACE,
590 "LastAddressConflict", append_ac_property, acd);
593 unsigned int acd_host_get_conflicts_count(struct acd_host *acd)
595 return acd->conflicts;