All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/7] acd: ACD skeleton
@ 2020-12-03 20:41 James Prestwood
  2020-12-03 20:41 ` [PATCH 2/7] acd: add ARP sockets, listener, and probing James Prestwood
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: James Prestwood @ 2020-12-03 20:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 6276 bytes --]

Initial skeleton APIs
---
 Makefile.am |   6 ++-
 ell/acd.c   | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 ell/acd.h   |  56 +++++++++++++++++++++++++
 ell/ell.h   |   1 +
 ell/ell.sym |   7 ++++
 5 files changed, 184 insertions(+), 2 deletions(-)
 create mode 100644 ell/acd.c
 create mode 100644 ell/acd.h

diff --git a/Makefile.am b/Makefile.am
index 28082aa..9bb106b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -58,7 +58,8 @@ pkginclude_HEADERS = ell/ell.h \
 			ell/time.h \
 			ell/gpio.h \
 			ell/path.h \
-			ell/icmp6.h
+			ell/icmp6.h \
+			ell/acd.h
 
 lib_LTLIBRARIES = ell/libell.la
 
@@ -141,7 +142,8 @@ ell_libell_la_SOURCES = $(linux_headers) \
 			ell/gpio.c \
 			ell/path.c \
 			ell/icmp6.c \
-			ell/icmp6-private.h
+			ell/icmp6-private.h \
+			ell/acd.c
 
 ell_libell_la_LDFLAGS = -Wl,--no-undefined \
 			-Wl,--version-script=$(top_srcdir)/ell/ell.sym \
diff --git a/ell/acd.c b/ell/acd.c
new file mode 100644
index 0000000..11bee06
--- /dev/null
+++ b/ell/acd.c
@@ -0,0 +1,116 @@
+/*
+ *  Embedded Linux library
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "private.h"
+#include "acd.h"
+#include "util.h"
+
+struct l_acd {
+	int ifindex;
+
+	uint32_t ip;
+
+	l_acd_event_func_t event_func;
+	l_acd_destroy_func_t destroy;
+	void *user_data;
+
+	l_acd_debug_cb_t debug_handler;
+	l_acd_destroy_func_t debug_destroy;
+	void *debug_data;
+};
+
+LIB_EXPORT struct l_acd *l_acd_new(int ifindex)
+{
+	struct l_acd *acd = l_new(struct l_acd, 1);
+
+	acd->ifindex = ifindex;
+
+	return acd;
+}
+
+LIB_EXPORT bool l_acd_start(struct l_acd *acd, const char *ip)
+{
+	struct in_addr ia;
+
+	if (unlikely(!acd || !ip))
+		return false;
+
+	if (inet_pton(AF_INET, ip, &ia) != 1)
+		return false;
+
+	acd->ip = ntohl(ia.s_addr);
+
+	return true;
+}
+
+LIB_EXPORT bool l_acd_set_event_handler(struct l_acd *acd,
+					l_acd_event_func_t cb,
+					void *user_data,
+					l_acd_destroy_func_t destroy)
+{
+	if (unlikely(!acd))
+		return false;
+
+	acd->event_func = cb;
+	acd->destroy = destroy;
+	acd->user_data = user_data;
+
+	return true;
+}
+
+LIB_EXPORT bool l_acd_stop(struct l_acd *acd)
+{
+	if (unlikely(!acd))
+		return false;
+
+	return true;
+}
+
+LIB_EXPORT void l_acd_destroy(struct l_acd *acd)
+{
+	if (unlikely(!acd))
+		return;
+
+	if (acd->destroy)
+		acd->destroy(acd->user_data);
+
+	l_free(acd);
+}
+
+LIB_EXPORT bool l_acd_set_debug(struct l_acd *acd,
+				l_acd_debug_cb_t function,
+				void *user_data, l_acd_destroy_func_t destory)
+{
+	if (unlikely(!acd))
+		return false;
+
+	acd->debug_handler = function;
+	acd->debug_data = user_data;
+	acd->debug_destroy = destory;
+
+	return true;
+}
diff --git a/ell/acd.h b/ell/acd.h
new file mode 100644
index 0000000..121d119
--- /dev/null
+++ b/ell/acd.h
@@ -0,0 +1,56 @@
+/*
+ *
+ *  Embedded Linux library
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __ELL_ACD_H
+#define __ELL_ACD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+struct l_acd;
+
+enum l_acd_event {
+	L_ACD_EVENT_AVAILABLE,
+	L_ACD_EVENT_CONFLICT,
+};
+
+typedef void (*l_acd_event_func_t)(enum l_acd_event event, void *user_data);
+typedef void (*l_acd_destroy_func_t)(void *user_data);
+
+typedef void (*l_acd_debug_cb_t)(const char *str, void *user_data);
+
+struct l_acd *l_acd_new(int ifindex);
+bool l_acd_start(struct l_acd *acd, const char *ip);
+bool l_acd_set_event_handler(struct l_acd *acd, l_acd_event_func_t cb,
+				void *user_data, l_acd_destroy_func_t destroy);
+bool l_acd_stop(struct l_acd *acd);
+void l_acd_destroy(struct l_acd *acd);
+bool l_acd_set_debug(struct l_acd *acd, l_acd_debug_cb_t function,
+			void *user_data, l_acd_destroy_func_t destory);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ELL_CERT_H */
diff --git a/ell/ell.h b/ell/ell.h
index ef5d83b..6662ad5 100644
--- a/ell/ell.h
+++ b/ell/ell.h
@@ -64,3 +64,4 @@
 #include <ell/time.h>
 #include <ell/gpio.h>
 #include <ell/path.h>
+#include <ell/acd.h>
diff --git a/ell/ell.sym b/ell/ell.sym
index 49689d1..b029b8c 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -654,6 +654,13 @@ global:
 	l_icmp6_client_set_route_priority;
 	l_icmp6_router_get_managed;
 	l_icmp6_router_get_other;
+	/* acd */
+	l_acd_new;
+	l_acd_start;
+	l_acd_set_event_handler;
+	l_acd_stop;
+	l_acd_destroy;
+	l_acd_set_debug;
 local:
 	*;
 };
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/7] acd: add ARP sockets, listener, and probing
  2020-12-03 20:41 [PATCH 1/7] acd: ACD skeleton James Prestwood
@ 2020-12-03 20:41 ` James Prestwood
  2020-12-04  6:50   ` Denis Kenzior
  2020-12-03 20:41 ` [PATCH 3/7] acd: add probe/annouce states, and announce address James Prestwood
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 8+ messages in thread
From: James Prestwood @ 2020-12-03 20:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 6784 bytes --]

Add support for opening the network socket, listening for
messages, and sending ARP probes.
---
 ell/acd.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 226 insertions(+)

diff --git a/ell/acd.c b/ell/acd.c
index 11bee06..f8f3df4 100644
--- a/ell/acd.c
+++ b/ell/acd.c
@@ -22,17 +22,52 @@
 #include <config.h>
 #endif
 
+#include <unistd.h>
 #include <sys/socket.h>
+#include <netpacket/packet.h>
+#include <netinet/if_ether.h>
+#include <net/if_arp.h>
 #include <arpa/inet.h>
 
 #include "private.h"
 #include "acd.h"
 #include "util.h"
+#include "io.h"
+#include "net.h"
+#include "timeout.h"
+#include "random.h"
+
+/* IPv4 Address Conflict Detection (RFC 5227) */
+#define PROBE_WAIT		1
+#define PROBE_NUM		3
+#define PROBE_MIN		1
+#define PROBE_MAX		2
+
+#define MAC "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_STR(a) a[0], a[1], a[2], a[3], a[4], a[5]
+
+#define IP_STR(uint_ip) \
+({ \
+	struct in_addr _in; \
+	char *_out; \
+	_in.s_addr = uint_ip; \
+	_out = inet_ntoa(_in); \
+	_out; \
+})
+
+#define ACD_DEBUG(fmt, args...)					\
+	l_util_debug(acd->debug_handler, acd->debug_data,		\
+			"%s:%i " fmt, __func__, __LINE__, ## args)
 
 struct l_acd {
 	int ifindex;
 
 	uint32_t ip;
+	uint8_t mac[ETH_ALEN];
+
+	struct l_io *io;
+	struct l_timeout *timeout;
+	unsigned int retries;
 
 	l_acd_event_func_t event_func;
 	l_acd_destroy_func_t destroy;
@@ -43,6 +78,158 @@ struct l_acd {
 	void *debug_data;
 };
 
+static int acd_open_socket(int ifindex)
+{
+	struct sockaddr_ll dest;
+	int fd;
+
+	fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+	if (fd < 0)
+		return -errno;
+
+	memset(&dest, 0, sizeof(dest));
+
+	dest.sll_family = AF_PACKET;
+	dest.sll_protocol = htons(ETH_P_ARP);
+	dest.sll_ifindex = ifindex;
+	dest.sll_halen = ETH_ALEN;
+	memset(dest.sll_addr, 0xFF, ETH_ALEN);
+
+	if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
+		int err = errno;
+		close(fd);
+		return -err;
+	}
+
+	return fd;
+}
+
+static int acd_send_packet(struct l_acd *acd, uint32_t source_ip)
+{
+	struct sockaddr_ll dest;
+	struct ether_arp p;
+	uint32_t ip_source;
+	uint32_t ip_target;
+	int n;
+	int fd = l_io_get_fd(acd->io);
+
+	memset(&dest, 0, sizeof(dest));
+
+	dest.sll_family = AF_PACKET;
+	dest.sll_protocol = htons(ETH_P_ARP);
+	dest.sll_ifindex = acd->ifindex;
+	dest.sll_halen = ETH_ALEN;
+	memset(dest.sll_addr, 0xFF, ETH_ALEN);
+
+	ip_source = htonl(source_ip);
+	ip_target = htonl(acd->ip);
+	p.arp_hrd = htons(ARPHRD_ETHER);
+	p.arp_pro = htons(ETHERTYPE_IP);
+	p.arp_hln = ETH_ALEN;
+	p.arp_pln = 4;
+	p.arp_op = htons(ARPOP_REQUEST);
+
+	ACD_DEBUG("sending packet with target IP %s", IP_STR(ip_target));
+
+	memcpy(&p.arp_sha, acd->mac, ETH_ALEN);
+	memcpy(&p.arp_spa, &ip_source, sizeof(p.arp_spa));
+	memcpy(&p.arp_tpa, &ip_target, sizeof(p.arp_tpa));
+
+	n = sendto(fd, &p, sizeof(p), 0,
+			(struct sockaddr*) &dest, sizeof(dest));
+	if (n < 0)
+		n = -errno;
+
+	return n;
+}
+
+static uint32_t acd_random_delay_ms(uint32_t max_sec)
+{
+	uint32_t rand;
+
+	l_getrandom(&rand, sizeof(rand));
+
+	return rand % (max_sec * 1000);
+}
+
+static void probe_wait_timeout(struct l_timeout *timeout, void *user_data)
+{
+	struct l_acd *acd = user_data;
+	uint32_t delay;
+
+	ACD_DEBUG("Sending ACD Probe");
+
+	l_timeout_remove(acd->timeout);
+	acd->timeout = NULL;
+
+	if (acd_send_packet(acd, 0) < 0) {
+		ACD_DEBUG("Failed to send ACD probe");
+		return;
+	}
+
+	acd->retries++;
+
+	if (acd->retries < PROBE_NUM) {
+		/*
+		 * RFC 5227 - Section 2.1.1
+		 *
+		 * "... and should then send PROBE_NUM probe packets, each of
+		 * these probe packets spaced randomly and uniformly, PROBE_MIN
+		 * to PROBE_MAX seconds apart."
+		 */
+		delay = acd_random_delay_ms(PROBE_MAX - PROBE_MIN);
+		delay += PROBE_MIN * 1000;
+		acd->timeout = l_timeout_create_ms(delay, probe_wait_timeout,
+							acd, NULL);
+	} else
+		ACD_DEBUG("Done probing");
+
+}
+
+static bool acd_read_handler(struct l_io *io, void *user_data)
+{
+	struct l_acd *acd = user_data;
+	struct ether_arp arp;
+	ssize_t len;
+	int source_conflict;
+	int target_conflict;
+	bool probe;
+	uint32_t ip;
+
+	memset(&arp, 0, sizeof(arp));
+	len = read(l_io_get_fd(acd->io), &arp, sizeof(arp));
+	if (len < 0)
+		return false;
+
+	if (len != sizeof(arp))
+		return true;
+
+	if (arp.arp_op != htons(ARPOP_REPLY) &&
+			arp.arp_op != htons(ARPOP_REQUEST))
+		return true;
+
+	if (memcmp(arp.arp_sha, acd->mac, ETH_ALEN) == 0)
+		return true;
+
+	ip = htonl(acd->ip);
+	source_conflict = !memcmp(arp.arp_spa, &ip, sizeof(uint32_t));
+	probe = l_memeqzero(arp.arp_spa, sizeof(uint32_t));
+	target_conflict = probe &&
+		!memcmp(arp.arp_tpa, &ip, sizeof(uint32_t));
+
+	if (!source_conflict && !target_conflict) {
+		ACD_DEBUG("No target or source conflict detected for %s",
+				IP_STR(ip));
+		return true;
+	}
+
+	ACD_DEBUG("%s conflict detected for %s",
+			target_conflict ? "Target" : "Source",
+			IP_STR(ip));
+
+	return true;
+}
+
 LIB_EXPORT struct l_acd *l_acd_new(int ifindex)
 {
 	struct l_acd *acd = l_new(struct l_acd, 1);
@@ -55,6 +242,8 @@ LIB_EXPORT struct l_acd *l_acd_new(int ifindex)
 LIB_EXPORT bool l_acd_start(struct l_acd *acd, const char *ip)
 {
 	struct in_addr ia;
+	int fd;
+	uint32_t delay;
 
 	if (unlikely(!acd || !ip))
 		return false;
@@ -62,8 +251,35 @@ LIB_EXPORT bool l_acd_start(struct l_acd *acd, const char *ip)
 	if (inet_pton(AF_INET, ip, &ia) != 1)
 		return false;
 
+	fd = acd_open_socket(acd->ifindex);
+	if (fd < 0)
+		return false;
+
+	if (l_memeqzero(acd->mac, ETH_ALEN) &&
+			!l_net_get_mac_address(acd->ifindex, acd->mac)) {
+		close(fd);
+		return false;
+	}
+
+	acd->io = l_io_new(fd);
+	l_io_set_close_on_destroy(acd->io, true);
+	l_io_set_read_handler(acd->io, acd_read_handler, acd, NULL);
+
 	acd->ip = ntohl(ia.s_addr);
 
+	delay = acd_random_delay_ms(PROBE_WAIT);
+
+	ACD_DEBUG("Waiting %ums to send probe", delay);
+
+	/*
+	 * RFC 5227 - Section 2.1.1
+	 * "When ready to begin probing, the host should then wait for a random
+	 *  time interval selected uniformly in the range zero to PROBE_WAIT
+	 *  seconds..."
+	 */
+	acd->timeout = l_timeout_create_ms(delay, probe_wait_timeout,
+							acd, NULL);
+
 	return true;
 }
 
@@ -87,6 +303,16 @@ LIB_EXPORT bool l_acd_stop(struct l_acd *acd)
 	if (unlikely(!acd))
 		return false;
 
+	if (acd->timeout) {
+		l_timeout_remove(acd->timeout);
+		acd->timeout = NULL;
+	}
+
+	if (acd->io) {
+		l_io_destroy(acd->io);
+		acd->io = NULL;
+	}
+
 	return true;
 }
 
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/7] acd: add probe/annouce states, and announce address
  2020-12-03 20:41 [PATCH 1/7] acd: ACD skeleton James Prestwood
  2020-12-03 20:41 ` [PATCH 2/7] acd: add ARP sockets, listener, and probing James Prestwood
@ 2020-12-03 20:41 ` James Prestwood
  2020-12-03 20:41 ` [PATCH 4/7] acd: add address defence and address lost events James Prestwood
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: James Prestwood @ 2020-12-03 20:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 3946 bytes --]

Tracks state (probe/annouce) and will stop probing if an address
conflict is detected. Once all probes have been sent the state
transitions to announce. At this point the IP is safe to use.

Events are now signaled for conflicts and available IPs.

Going forward, the ANNOUNCED state will be the normal state the
ACD client is in while monitoring for conflicting packets.
---
 ell/acd.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 80 insertions(+), 4 deletions(-)

diff --git a/ell/acd.c b/ell/acd.c
index f8f3df4..4528d76 100644
--- a/ell/acd.c
+++ b/ell/acd.c
@@ -43,6 +43,10 @@
 #define PROBE_MIN		1
 #define PROBE_MAX		2
 
+#define ANNOUNCE_WAIT		2
+#define ANNOUNCE_NUM		2
+#define ANNOUNCE_INTERVAL	2
+
 #define MAC "%02x:%02x:%02x:%02x:%02x:%02x"
 #define MAC_STR(a) a[0], a[1], a[2], a[3], a[4], a[5]
 
@@ -59,12 +63,19 @@
 	l_util_debug(acd->debug_handler, acd->debug_data,		\
 			"%s:%i " fmt, __func__, __LINE__, ## args)
 
+enum acd_state {
+	ACD_STATE_PROBE,
+	ACD_STATE_ANNOUNCED,
+};
+
 struct l_acd {
 	int ifindex;
 
 	uint32_t ip;
 	uint8_t mac[ETH_ALEN];
 
+	enum acd_state state;
+
 	struct l_io *io;
 	struct l_timeout *timeout;
 	unsigned int retries;
@@ -152,6 +163,49 @@ static uint32_t acd_random_delay_ms(uint32_t max_sec)
 	return rand % (max_sec * 1000);
 }
 
+static void announce_wait_timeout(struct l_timeout *timeout, void *user_data)
+{
+	struct l_acd *acd = user_data;
+
+	l_timeout_remove(acd->timeout);
+	acd->timeout = NULL;
+
+	if (acd->state == ACD_STATE_PROBE) {
+		ACD_DEBUG("No conflicts found for %s, announcing address",
+				IP_STR(htonl(acd->ip)));
+
+		acd->state = ACD_STATE_ANNOUNCED;
+
+		/*
+		 * RFC 5227 - Section 2.3
+		 *
+		 * "The host may begin legitimately using the IP address
+		 *  immediately after sending the first of the two ARP
+		 *  Announcements"
+		 */
+
+		if (acd->event_func)
+			acd->event_func(L_ACD_EVENT_AVAILABLE, acd->user_data);
+	}
+
+	if (acd->retries != ANNOUNCE_NUM) {
+		acd->retries++;
+
+		if (acd_send_packet(acd, acd->ip) < 0) {
+			ACD_DEBUG("Failed to send ACD announcement");
+			return;
+		}
+
+		acd->timeout = l_timeout_create(ANNOUNCE_INTERVAL,
+						announce_wait_timeout,
+						acd, NULL);
+
+		return;
+	}
+
+	ACD_DEBUG("Done announcing");
+}
+
 static void probe_wait_timeout(struct l_timeout *timeout, void *user_data)
 {
 	struct l_acd *acd = user_data;
@@ -181,9 +235,19 @@ static void probe_wait_timeout(struct l_timeout *timeout, void *user_data)
 		delay += PROBE_MIN * 1000;
 		acd->timeout = l_timeout_create_ms(delay, probe_wait_timeout,
 							acd, NULL);
-	} else
+	} else {
+		/*
+		 * Wait for ANNOUNCE_WAIT seconds after probe period before
+		 * announcing address.
+		 */
 		ACD_DEBUG("Done probing");
 
+		acd->retries = 1;
+
+		acd->timeout = l_timeout_create(ANNOUNCE_WAIT,
+							announce_wait_timeout,
+							acd, NULL);
+	}
 }
 
 static bool acd_read_handler(struct l_io *io, void *user_data)
@@ -223,9 +287,20 @@ static bool acd_read_handler(struct l_io *io, void *user_data)
 		return true;
 	}
 
-	ACD_DEBUG("%s conflict detected for %s",
-			target_conflict ? "Target" : "Source",
-			IP_STR(ip));
+	switch (acd->state) {
+	case ACD_STATE_PROBE:
+		/* No reason to continue probing */
+		ACD_DEBUG("%s conflict detected for %s",
+				target_conflict ? "Target" : "Source",
+				IP_STR(ip));
+
+		if (acd->event_func)
+			acd->event_func(L_ACD_EVENT_CONFLICT, acd->user_data);
+
+		l_acd_stop(acd);
+	case ACD_STATE_ANNOUNCED:
+		break;
+	}
 
 	return true;
 }
@@ -266,6 +341,7 @@ LIB_EXPORT bool l_acd_start(struct l_acd *acd, const char *ip)
 	l_io_set_read_handler(acd->io, acd_read_handler, acd, NULL);
 
 	acd->ip = ntohl(ia.s_addr);
+	acd->state = ACD_STATE_PROBE;
 
 	delay = acd_random_delay_ms(PROBE_WAIT);
 
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/7] acd: add address defence and address lost events
  2020-12-03 20:41 [PATCH 1/7] acd: ACD skeleton James Prestwood
  2020-12-03 20:41 ` [PATCH 2/7] acd: add ARP sockets, listener, and probing James Prestwood
  2020-12-03 20:41 ` [PATCH 3/7] acd: add probe/annouce states, and announce address James Prestwood
@ 2020-12-03 20:41 ` James Prestwood
  2020-12-03 20:41 ` [PATCH 5/7] acd: add l_acd_set_skip_probes James Prestwood
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: James Prestwood @ 2020-12-03 20:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 3207 bytes --]

---
 ell/acd.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ell/acd.h |  1 +
 2 files changed, 69 insertions(+)

diff --git a/ell/acd.c b/ell/acd.c
index 4528d76..8fa8d95 100644
--- a/ell/acd.c
+++ b/ell/acd.c
@@ -47,6 +47,8 @@
 #define ANNOUNCE_NUM		2
 #define ANNOUNCE_INTERVAL	2
 
+#define DEFEND_INTERVAL		10
+
 #define MAC "%02x:%02x:%02x:%02x:%02x:%02x"
 #define MAC_STR(a) a[0], a[1], a[2], a[3], a[4], a[5]
 
@@ -66,6 +68,7 @@
 enum acd_state {
 	ACD_STATE_PROBE,
 	ACD_STATE_ANNOUNCED,
+	ACD_STATE_DEFEND,
 };
 
 struct l_acd {
@@ -250,6 +253,17 @@ static void probe_wait_timeout(struct l_timeout *timeout, void *user_data)
 	}
 }
 
+static void defend_wait_timeout(struct l_timeout *timeout, void *user_data)
+{
+	struct l_acd *acd = user_data;
+
+	l_timeout_remove(acd->timeout);
+	acd->timeout = NULL;
+
+	/* Successfully defended address */
+	acd->state = ACD_STATE_ANNOUNCED;
+}
+
 static bool acd_read_handler(struct l_io *io, void *user_data)
 {
 	struct l_acd *acd = user_data;
@@ -298,7 +312,61 @@ static bool acd_read_handler(struct l_io *io, void *user_data)
 			acd->event_func(L_ACD_EVENT_CONFLICT, acd->user_data);
 
 		l_acd_stop(acd);
+
+		break;
 	case ACD_STATE_ANNOUNCED:
+		/* Only defend packets with a source conflict */
+		if (!source_conflict)
+			return true;
+
+		/*
+		 * RFC 5227 - Section 2.4 (b)
+		 * [If the host] "has not seen any other conflicting ARP packets
+		 * within the last DEFEND_INTERVAL seconds, MAY elect to attempt
+		 * to defend its address by recording the time that the
+		 * conflicting ARP packet was received, and then broadcasting
+		 * one single ARP Announcement"
+		 */
+		acd->state = ACD_STATE_DEFEND;
+
+		/*
+		 * We still have an initial announcement to send, but rather
+		 * than wait for that (potentially 2 seconds) we can remove
+		 * the timeout, send annouce now, and still transition to the
+		 * defending state.
+		 */
+		if (acd->timeout)
+			l_timeout_remove(acd->timeout);
+
+		acd_send_packet(acd, acd->ip);
+
+		ACD_DEBUG("Defending address");
+
+		acd->timeout = l_timeout_create(DEFEND_INTERVAL,
+						defend_wait_timeout, acd, NULL);
+
+		break;
+	case ACD_STATE_DEFEND:
+		if (!source_conflict)
+			return true;
+
+		l_timeout_remove(acd->timeout);
+		acd->timeout = NULL;
+
+		ACD_DEBUG("Lost address");
+		/*
+		* RFC 5227 Section 2.4(b)
+		* "if this is not the first conflicting ARP packet the host has seen,
+		* and the time recorded for the previous conflicting ARP packet is
+		* recent, within DEFEND_INTERVAL seconds, then the host MUST
+		* immediately cease using this address and signal an error to the
+		* configuring agent"
+		*/
+		if (acd->event_func)
+			acd->event_func(L_ACD_EVENT_LOST, acd->user_data);
+
+		l_acd_stop(acd);
+
 		break;
 	}
 
diff --git a/ell/acd.h b/ell/acd.h
index 121d119..21a6958 100644
--- a/ell/acd.h
+++ b/ell/acd.h
@@ -34,6 +34,7 @@ struct l_acd;
 enum l_acd_event {
 	L_ACD_EVENT_AVAILABLE,
 	L_ACD_EVENT_CONFLICT,
+	L_ACD_EVENT_LOST,
 };
 
 typedef void (*l_acd_event_func_t)(enum l_acd_event event, void *user_data);
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 5/7] acd: add l_acd_set_skip_probes
  2020-12-03 20:41 [PATCH 1/7] acd: ACD skeleton James Prestwood
                   ` (2 preceding siblings ...)
  2020-12-03 20:41 ` [PATCH 4/7] acd: add address defence and address lost events James Prestwood
@ 2020-12-03 20:41 ` James Prestwood
  2020-12-03 20:41 ` [PATCH 6/7] acd: add defend policy concept James Prestwood
  2020-12-03 20:41 ` [PATCH 7/7] examples: add acd client implementation James Prestwood
  5 siblings, 0 replies; 8+ messages in thread
From: James Prestwood @ 2020-12-03 20:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2486 bytes --]

Allow skipping the probe stage. Probes take a significant
amount of time, and in cases where the network is properly
configured (e.g. a DHCP server) there really isn't a need
for the probe stage.
---
 ell/acd.c   | 35 ++++++++++++++++++++++++++++++++++-
 ell/acd.h   |  1 +
 ell/ell.sym |  1 +
 3 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/ell/acd.c b/ell/acd.c
index 8fa8d95..2c8d788 100644
--- a/ell/acd.c
+++ b/ell/acd.c
@@ -90,6 +90,8 @@ struct l_acd {
 	l_acd_debug_cb_t debug_handler;
 	l_acd_destroy_func_t debug_destroy;
 	void *debug_data;
+
+	bool skip_probes : 1;
 };
 
 static int acd_open_socket(int ifindex)
@@ -409,7 +411,24 @@ LIB_EXPORT bool l_acd_start(struct l_acd *acd, const char *ip)
 	l_io_set_read_handler(acd->io, acd_read_handler, acd, NULL);
 
 	acd->ip = ntohl(ia.s_addr);
-	acd->state = ACD_STATE_PROBE;
+
+	/*
+	 * Optimization to allows skipping the probe stage. The RFC does not
+	 * mention allowing this, but probes take an eternity and would
+	 * drastically increase connection times for wifi/eth. It is still
+	 * recommended that probes be used for statically configured IP's where
+	 * no DHCP server is involved.
+	 */
+	if (acd->skip_probes) {
+		ACD_DEBUG("Skipping probes and sending announcements");
+
+		acd->retries = 1;
+
+		announce_wait_timeout(NULL, acd);
+
+		return true;
+	} else
+		acd->state = ACD_STATE_PROBE;
 
 	delay = acd_random_delay_ms(PROBE_WAIT);
 
@@ -484,3 +503,17 @@ LIB_EXPORT bool l_acd_set_debug(struct l_acd *acd,
 
 	return true;
 }
+
+LIB_EXPORT bool l_acd_set_skip_probes(struct l_acd *acd, bool skip)
+{
+	if (unlikely(!acd))
+		return false;
+
+	/* ACD has already been started */
+	if (acd->io)
+		return false;
+
+	acd->skip_probes = skip;
+
+	return true;
+}
diff --git a/ell/acd.h b/ell/acd.h
index 21a6958..eba504d 100644
--- a/ell/acd.h
+++ b/ell/acd.h
@@ -50,6 +50,7 @@ bool l_acd_stop(struct l_acd *acd);
 void l_acd_destroy(struct l_acd *acd);
 bool l_acd_set_debug(struct l_acd *acd, l_acd_debug_cb_t function,
 			void *user_data, l_acd_destroy_func_t destory);
+bool l_acd_set_skip_probes(struct l_acd *acd, bool skip);
 #ifdef __cplusplus
 }
 #endif
diff --git a/ell/ell.sym b/ell/ell.sym
index b029b8c..a566a83 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -661,6 +661,7 @@ global:
 	l_acd_stop;
 	l_acd_destroy;
 	l_acd_set_debug;
+	l_acd_set_skip_probes;
 local:
 	*;
 };
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6/7] acd: add defend policy concept
  2020-12-03 20:41 [PATCH 1/7] acd: ACD skeleton James Prestwood
                   ` (3 preceding siblings ...)
  2020-12-03 20:41 ` [PATCH 5/7] acd: add l_acd_set_skip_probes James Prestwood
@ 2020-12-03 20:41 ` James Prestwood
  2020-12-03 20:41 ` [PATCH 7/7] examples: add acd client implementation James Prestwood
  5 siblings, 0 replies; 8+ messages in thread
From: James Prestwood @ 2020-12-03 20:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 4648 bytes --]

The ACD RFC defines 3 possible policies for defending an address:

a) Give up address immediately (L_ACD_DEFEND_POLICY_NONE)
b) Send single annoucement (L_ACD_DEFEND_POLICY_DEFEND)
c) Defend infinitely (L_ACD_DEFEND_POLICY_INFINITE)

The policy can be set to a stopped/not started ACD object by
calling l_acd_set_defend_policy.

In the event of a lost address (a or b) ACD will be stopped and
the LOST event will be generated. If an infinite policy (c) is
used, the ACD client will not be stopped and no events will fire.
ACD will continue defending the address by sending sending a
single annoucement every 10 seconds while conflicting packets are
still being received.
---
 ell/acd.c   | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 ell/acd.h   |  8 ++++++++
 ell/ell.sym |  1 +
 3 files changed, 68 insertions(+)

diff --git a/ell/acd.c b/ell/acd.c
index 2c8d788..ef72fef 100644
--- a/ell/acd.c
+++ b/ell/acd.c
@@ -78,6 +78,7 @@ struct l_acd {
 	uint8_t mac[ETH_ALEN];
 
 	enum acd_state state;
+	enum l_acd_defend_policy policy;
 
 	struct l_io *io;
 	struct l_timeout *timeout;
@@ -321,6 +322,25 @@ static bool acd_read_handler(struct l_io *io, void *user_data)
 		if (!source_conflict)
 			return true;
 
+		/*
+		 * RFC 5227 - Section 2.4 (a)
+		 *
+		 * "Upon receiving a conflicting ARP packet, a host MAY elect to
+		 * immediately cease using the address, and signal an error to
+		 * the configuring agent as described above."
+		 */
+		if (acd->policy == L_ACD_DEFEND_POLICY_NONE) {
+			ACD_DEBUG("Conflict detected, giving up address");
+
+			if (acd->event_func)
+				acd->event_func(L_ACD_EVENT_LOST,
+							acd->user_data);
+
+			l_acd_stop(acd);
+
+			break;
+		}
+
 		/*
 		 * RFC 5227 - Section 2.4 (b)
 		 * [If the host] "has not seen any other conflicting ARP packets
@@ -352,6 +372,29 @@ static bool acd_read_handler(struct l_io *io, void *user_data)
 		if (!source_conflict)
 			return true;
 
+		/*
+		 * RFC 5227 Section 2.4 (c)
+		 * "If a host has been configured such that it should not give
+		 * up its address under any circumstances ... then it MAY elect
+		 * to defend its address indefinitely."
+		 */
+		if (acd->policy == L_ACD_DEFEND_POLICY_INFINITE) {
+			ACD_DEBUG("Conflict "MAC" found with infinite policy",
+					MAC_STR(arp.arp_sha));
+
+			/*
+			 * Nothing to do at this point. We are in the DEFEND
+			 * state meaning there is a defend wait timeout pending.
+			 * Once that fires it will transition back into
+			 * ANNOUNCED. Once in ANNOUNCED and another conflict is
+			 * received, a single announcement will be sent. This
+			 * ensures a maximum of only 1 announcement every
+			 * DEFEND_INTERVAL seconds as long as conflicting
+			 * packets are being received.
+			 */
+			break;
+		}
+
 		l_timeout_remove(acd->timeout);
 		acd->timeout = NULL;
 
@@ -380,6 +423,7 @@ LIB_EXPORT struct l_acd *l_acd_new(int ifindex)
 	struct l_acd *acd = l_new(struct l_acd, 1);
 
 	acd->ifindex = ifindex;
+	acd->policy = L_ACD_DEFEND_POLICY_DEFEND;
 
 	return acd;
 }
@@ -517,3 +561,18 @@ LIB_EXPORT bool l_acd_set_skip_probes(struct l_acd *acd, bool skip)
 
 	return true;
 }
+
+LIB_EXPORT bool l_acd_set_defend_policy(struct l_acd *acd,
+				enum l_acd_defend_policy policy)
+{
+	if (unlikely(!acd))
+		return false;
+
+	/* ACD has already been started */
+	if (acd->io)
+		return false;
+
+	acd->policy = policy;
+
+	return true;
+}
diff --git a/ell/acd.h b/ell/acd.h
index eba504d..f537536 100644
--- a/ell/acd.h
+++ b/ell/acd.h
@@ -37,6 +37,12 @@ enum l_acd_event {
 	L_ACD_EVENT_LOST,
 };
 
+enum l_acd_defend_policy {
+	L_ACD_DEFEND_POLICY_NONE,	/* Never defend */
+	L_ACD_DEFEND_POLICY_DEFEND,	/* Default, defend once */
+	L_ACD_DEFEND_POLICY_INFINITE,	/* Defend indefinitely */
+};
+
 typedef void (*l_acd_event_func_t)(enum l_acd_event event, void *user_data);
 typedef void (*l_acd_destroy_func_t)(void *user_data);
 
@@ -51,6 +57,8 @@ void l_acd_destroy(struct l_acd *acd);
 bool l_acd_set_debug(struct l_acd *acd, l_acd_debug_cb_t function,
 			void *user_data, l_acd_destroy_func_t destory);
 bool l_acd_set_skip_probes(struct l_acd *acd, bool skip);
+bool l_acd_set_defend_policy(struct l_acd *acd,
+				enum l_acd_defend_policy policy);
 #ifdef __cplusplus
 }
 #endif
diff --git a/ell/ell.sym b/ell/ell.sym
index a566a83..d94b585 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -662,6 +662,7 @@ global:
 	l_acd_destroy;
 	l_acd_set_debug;
 	l_acd_set_skip_probes;
+	l_acd_set_defend_policy;
 local:
 	*;
 };
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 7/7] examples: add acd client implementation
  2020-12-03 20:41 [PATCH 1/7] acd: ACD skeleton James Prestwood
                   ` (4 preceding siblings ...)
  2020-12-03 20:41 ` [PATCH 6/7] acd: add defend policy concept James Prestwood
@ 2020-12-03 20:41 ` James Prestwood
  5 siblings, 0 replies; 8+ messages in thread
From: James Prestwood @ 2020-12-03 20:41 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 5337 bytes --]

Very basic ACD client which takes an ifindex and IP and performs
ACD on the network.
---
 Makefile.am           |   3 +-
 examples/acd-client.c | 166 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 168 insertions(+), 1 deletion(-)
 create mode 100644 examples/acd-client.c

diff --git a/Makefile.am b/Makefile.am
index 9bb106b..df4bfff 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -335,7 +335,7 @@ unit_test_data_files = unit/settings.test unit/dbus.conf
 examples = examples/dbus-service examples/https-client-test \
 		examples/https-server-test examples/dbus-client \
 		examples/dhcp-client examples/dhcp6-client \
-		examples/dhcp-server
+		examples/dhcp-server examples/acd-client
 
 if GLIB
 examples += examples/glib-eventloop
@@ -354,6 +354,7 @@ examples_glib_eventloop_LDADD = ell/libell-private.la @GLIB_LIBS@
 examples_dhcp_client_LDADD = ell/libell-private.la
 examples_dhcp6_client_LDADD = ell/libell-private.la
 examples_dhcp_server_LDADD = ell/libell-private.la
+examples_acd_client_LDADD = ell/libell-private.la
 
 noinst_PROGRAMS += tools/certchain-verify tools/genl-discover \
 		   tools/genl-watch tools/genl-request tools/gpio
diff --git a/examples/acd-client.c b/examples/acd-client.c
new file mode 100644
index 0000000..e737288
--- /dev/null
+++ b/examples/acd-client.c
@@ -0,0 +1,166 @@
+/*
+ *
+ *  Embedded Linux library
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <linux/if_arp.h>
+#include <getopt.h>
+
+#include <ell/ell.h>
+
+static enum l_acd_defend_policy policy = L_ACD_DEFEND_POLICY_DEFEND;
+
+static void do_debug(const char *str, void *user_data)
+{
+	const char *prefix = user_data;
+
+	l_info("%s%s", prefix, str);
+}
+
+static void signal_handler(uint32_t signo, void *user_data)
+{
+	switch (signo) {
+	case SIGINT:
+	case SIGTERM:
+		l_info("Terminate");
+		l_main_quit();
+		break;
+	}
+}
+
+static void event_handler(enum l_acd_event event, void *user_data)
+{
+	char *ip = user_data;
+
+	switch (event) {
+	case L_ACD_EVENT_CONFLICT:
+		l_info("IP %s conflicts with another host", ip);
+		break;
+	case L_ACD_EVENT_AVAILABLE:
+		l_info("IP %s is available", ip);
+		break;
+	case L_ACD_EVENT_LOST:
+		l_info("IP %s has been lost", ip);
+		l_main_quit();
+		break;
+	}
+
+	if (policy == L_ACD_DEFEND_POLICY_NONE)
+		l_main_quit();
+}
+
+static void usage(void)
+{
+	printf("acd-client usage\n"
+		"Usage:\n");
+	printf("\tacd-client <ifindex> <ip> [options]\n");
+	printf("Options:\n"
+		"\t-D, --defend [=policy] Keep running to defend address, "
+			"optionally by policy:\n"
+			"\t\tnone: never defend\n"
+			"\t\tdefend: defend once (default)\n"
+			"\t\tinfinite: defend infinitely\n"
+		"\t-n, --no-probes       Disable initial probe stage\n"
+		"\t-d, --debug           Run with debugging on\n");
+}
+
+static const struct option main_options[] = {
+	{ "defend",	 optional_argument,	NULL, 'D' },
+	{ "no-probes",	 no_argument,		NULL, 'n' },
+	{ "debug",	 no_argument,		NULL, 'd' },
+	{ }
+};
+
+int main(int argc, char *argv[])
+{
+	struct l_acd *acd;
+	int ifindex;
+	bool debug = false;
+	bool no_probe = false;
+
+	l_log_set_stderr();
+	l_debug_enable("*");
+
+	if (argc < 3) {
+		usage();
+		exit(0);
+	}
+
+	for (;;) {
+		int opt;
+
+		opt = getopt_long(argc - 2, argv + 2, "ndD::",
+					main_options, NULL);
+		if (opt < 0)
+			break;
+
+		switch (opt) {
+		case 'D':
+			if (optarg) {
+				if (!strcmp(optarg, "infinite"))
+					policy = L_ACD_DEFEND_POLICY_INFINITE;
+				else if (!strcmp(optarg, "none"))
+					policy = L_ACD_DEFEND_POLICY_NONE;
+			}
+
+			break;
+		case 'n':
+			no_probe = true;
+			break;
+		case 'd':
+			debug = true;
+			break;
+		}
+	}
+
+	ifindex = atoi(argv[1]);
+
+	if (!l_main_init())
+		return -1;
+
+	acd = l_acd_new(ifindex);
+	l_acd_set_skip_probes(acd, no_probe);
+	l_acd_set_defend_policy(acd, policy);
+
+	if (debug) {
+		l_acd_set_debug(acd, do_debug, "[ACD] ", NULL);
+		l_info("Set debug");
+	}
+	l_acd_set_event_handler(acd, event_handler, argv[2], NULL);
+	l_acd_start(acd, argv[2]);
+
+	l_main_run_with_signal(signal_handler, NULL);
+
+	l_acd_destroy(acd);
+	l_main_exit();
+
+	return 0;
+}
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/7] acd: add ARP sockets, listener, and probing
  2020-12-03 20:41 ` [PATCH 2/7] acd: add ARP sockets, listener, and probing James Prestwood
@ 2020-12-04  6:50   ` Denis Kenzior
  0 siblings, 0 replies; 8+ messages in thread
From: Denis Kenzior @ 2020-12-04  6:50 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2322 bytes --]

Hi James,

On 12/3/20 2:41 PM, James Prestwood wrote:
> Add support for opening the network socket, listening for
> messages, and sending ARP probes.
> ---
>   ell/acd.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 226 insertions(+)
> 

This looks really nice! I took the entire series and applied it.  Just have a 
few minor nitpicks you can fix later if you think worthwhile:

> +static int acd_send_packet(struct l_acd *acd, uint32_t source_ip)
> +{
> +	struct sockaddr_ll dest;
> +	struct ether_arp p;
> +	uint32_t ip_source;
> +	uint32_t ip_target;
> +	int n;
> +	int fd = l_io_get_fd(acd->io);
> +
> +	memset(&dest, 0, sizeof(dest));
> +
> +	dest.sll_family = AF_PACKET;
> +	dest.sll_protocol = htons(ETH_P_ARP);
> +	dest.sll_ifindex = acd->ifindex;
> +	dest.sll_halen = ETH_ALEN;
> +	memset(dest.sll_addr, 0xFF, ETH_ALEN);
> +
> +	ip_source = htonl(source_ip);
> +	ip_target = htonl(acd->ip);

Is there an advantage to storing acd->ip or source_ip in host byte order?  Since 
inet_pton already gives a network-order address, this seems like just extra 
cycles wasted.

> +	p.arp_hrd = htons(ARPHRD_ETHER);
> +	p.arp_pro = htons(ETHERTYPE_IP);
> +	p.arp_hln = ETH_ALEN;
> +	p.arp_pln = 4;
> +	p.arp_op = htons(ARPOP_REQUEST);
> +
> +	ACD_DEBUG("sending packet with target IP %s", IP_STR(ip_target));
> +
> +	memcpy(&p.arp_sha, acd->mac, ETH_ALEN);
> +	memcpy(&p.arp_spa, &ip_source, sizeof(p.arp_spa));
> +	memcpy(&p.arp_tpa, &ip_target, sizeof(p.arp_tpa));
> +
> +	n = sendto(fd, &p, sizeof(p), 0,
> +			(struct sockaddr*) &dest, sizeof(dest));
> +	if (n < 0)
> +		n = -errno;
> +
> +	return n;
> +}
> +
> +static uint32_t acd_random_delay_ms(uint32_t max_sec)
> +{
> +	uint32_t rand;
> +
> +	l_getrandom(&rand, sizeof(rand));
> +
> +	return rand % (max_sec * 1000);
> +}
> +

Consider using _time_pick_interval_secs() from time.c

> +static void probe_wait_timeout(struct l_timeout *timeout, void *user_data)
> +{
> +	struct l_acd *acd = user_data;
> +	uint32_t delay;
> +
> +	ACD_DEBUG("Sending ACD Probe");
> +
> +	l_timeout_remove(acd->timeout);
> +	acd->timeout = NULL;
> +

If you're going to re-start the timeout, it is slightly cheaper to use 
l_timeout_modify* instead.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2020-12-04  6:50 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-03 20:41 [PATCH 1/7] acd: ACD skeleton James Prestwood
2020-12-03 20:41 ` [PATCH 2/7] acd: add ARP sockets, listener, and probing James Prestwood
2020-12-04  6:50   ` Denis Kenzior
2020-12-03 20:41 ` [PATCH 3/7] acd: add probe/annouce states, and announce address James Prestwood
2020-12-03 20:41 ` [PATCH 4/7] acd: add address defence and address lost events James Prestwood
2020-12-03 20:41 ` [PATCH 5/7] acd: add l_acd_set_skip_probes James Prestwood
2020-12-03 20:41 ` [PATCH 6/7] acd: add defend policy concept James Prestwood
2020-12-03 20:41 ` [PATCH 7/7] examples: add acd client implementation James Prestwood

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.