1 /*
2  * Copyright (c) 2017 Matthias Boesl
3  * Copyright (c) 2018 Intel Corporation
4  * Copyright (c) 2024 Nordic Semiconductor ASA
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 /** @file
10  * @brief IPv4 address conflict detection
11  */
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(net_ipv4_acd, CONFIG_NET_IPV4_ACD_LOG_LEVEL);
15 
16 #include <zephyr/net/ethernet.h>
17 #include <zephyr/net/net_if.h>
18 #include <zephyr/net/net_l2.h>
19 #include <zephyr/net/net_mgmt.h>
20 #include <zephyr/net/net_pkt.h>
21 #include <zephyr/random/random.h>
22 #include <zephyr/sys/slist.h>
23 
24 #include "ipv4.h"
25 #include "net_private.h"
26 #include "../l2/ethernet/arp.h"
27 
28 static K_MUTEX_DEFINE(lock);
29 
30 /* Address conflict detection timer. */
31 static struct k_work_delayable ipv4_acd_timer;
32 
33 /* List of IPv4 addresses under an active conflict detection. */
34 static sys_slist_t active_acd_timers;
35 
36 #define BUF_ALLOC_TIMEOUT K_MSEC(100)
37 
38 /* Initial random delay*/
39 #define IPV4_ACD_PROBE_WAIT 1
40 
41 /* Number of probe packets */
42 #define IPV4_ACD_PROBE_NUM 3
43 
44 /* Minimum delay till repeated probe */
45 #define IPV4_ACD_PROBE_MIN 1
46 
47 /* Maximum delay till repeated probe */
48 #define IPV4_ACD_PROBE_MAX 2
49 
50 /* Delay before announcing */
51 #define IPV4_ACD_ANNOUNCE_WAIT 2
52 
53 /* Number of announcement packets */
54 #define IPV4_ACD_ANNOUNCE_NUM 2
55 
56 /* Time between announcement packets */
57 #define IPV4_ACD_ANNOUNCE_INTERVAL 2
58 
59 /* Max conflicts before rate limiting */
60 #define IPV4_ACD_MAX_CONFLICTS 10
61 
62 /* Delay between successive attempts */
63 #define IPV4_ACD_RATE_LIMIT_INTERVAL 60
64 
65 /* Minimum interval between defensive ARPs */
66 #define IPV4_ACD_DEFEND_INTERVAL 10
67 
68 enum ipv4_acd_state {
69 	IPV4_ACD_PROBE,    /* Probing state */
70 	IPV4_ACD_ANNOUNCE, /* Announce state */
71 };
72 
ipv4_acd_prepare_arp(struct net_if * iface,struct in_addr * sender_ip,struct in_addr * target_ip)73 static struct net_pkt *ipv4_acd_prepare_arp(struct net_if *iface,
74 					    struct in_addr *sender_ip,
75 					    struct in_addr *target_ip)
76 {
77 	struct net_pkt *pkt, *arp;
78 	int ret;
79 
80 	/* We provide AF_UNSPEC to the allocator: this packet does not
81 	 * need space for any IPv4 header.
82 	 */
83 	pkt = net_pkt_alloc_with_buffer(iface, sizeof(struct net_arp_hdr),
84 					AF_UNSPEC, 0, BUF_ALLOC_TIMEOUT);
85 	if (!pkt) {
86 		return NULL;
87 	}
88 
89 	net_pkt_set_family(pkt, AF_INET);
90 	net_pkt_set_ipv4_acd(pkt, true);
91 
92 	ret = net_arp_prepare(pkt, target_ip, sender_ip, &arp);
93 	if (ret == NET_ARP_PKT_REPLACED) {
94 		pkt = arp;
95 	} else if (ret < 0)  {
96 		pkt = NULL;
97 	}
98 	return pkt;
99 }
100 
ipv4_acd_send_probe(struct net_if_addr * ifaddr)101 static void ipv4_acd_send_probe(struct net_if_addr *ifaddr)
102 {
103 	struct net_if *iface = net_if_get_by_index(ifaddr->ifindex);
104 	struct in_addr unspecified = { 0 };
105 	struct net_pkt *pkt;
106 
107 	pkt = ipv4_acd_prepare_arp(iface, &unspecified, &ifaddr->address.in_addr);
108 	if (!pkt) {
109 		NET_DBG("Failed to prepare probe %p", iface);
110 		return;
111 	}
112 
113 	if (net_if_send_data(iface, pkt) == NET_DROP) {
114 		net_pkt_unref(pkt);
115 	}
116 }
117 
ipv4_acd_send_announcement(struct net_if_addr * ifaddr)118 static void ipv4_acd_send_announcement(struct net_if_addr *ifaddr)
119 {
120 	struct net_if *iface = net_if_get_by_index(ifaddr->ifindex);
121 	struct net_pkt *pkt;
122 
123 	pkt = ipv4_acd_prepare_arp(iface, &ifaddr->address.in_addr,
124 				   &ifaddr->address.in_addr);
125 	if (!pkt) {
126 		NET_DBG("Failed to prepare announcement %p", iface);
127 		return;
128 	}
129 
130 	if (net_if_send_data(iface, pkt) == NET_DROP) {
131 		net_pkt_unref(pkt);
132 	}
133 }
134 
acd_timer_reschedule(void)135 static void acd_timer_reschedule(void)
136 {
137 	k_timepoint_t expiry = sys_timepoint_calc(K_FOREVER);
138 	k_timeout_t timeout;
139 	sys_snode_t *node;
140 
141 	SYS_SLIST_FOR_EACH_NODE(&active_acd_timers, node) {
142 		struct net_if_addr *ifaddr =
143 			CONTAINER_OF(node, struct net_if_addr, acd_node);
144 
145 		if (sys_timepoint_cmp(ifaddr->acd_timeout, expiry) < 0) {
146 			expiry = ifaddr->acd_timeout;
147 		}
148 	}
149 
150 	timeout = sys_timepoint_timeout(expiry);
151 	if (K_TIMEOUT_EQ(timeout, K_FOREVER)) {
152 		k_work_cancel_delayable(&ipv4_acd_timer);
153 		return;
154 	}
155 
156 	k_work_reschedule(&ipv4_acd_timer, timeout);
157 }
158 
ipv4_acd_manage_timeout(struct net_if_addr * ifaddr)159 static void ipv4_acd_manage_timeout(struct net_if_addr *ifaddr)
160 {
161 	switch (ifaddr->acd_state) {
162 	case IPV4_ACD_PROBE:
163 		if (ifaddr->acd_count < IPV4_ACD_PROBE_NUM) {
164 			uint32_t delay;
165 
166 			NET_DBG("Sending probe for %s",
167 				net_sprint_ipv4_addr(&ifaddr->address.in_addr));
168 
169 			ipv4_acd_send_probe(ifaddr);
170 
171 			ifaddr->acd_count++;
172 			if (ifaddr->acd_count < IPV4_ACD_PROBE_NUM) {
173 				delay = sys_rand32_get();
174 				delay %= MSEC_PER_SEC * (IPV4_ACD_PROBE_MAX - IPV4_ACD_PROBE_MIN);
175 				delay += MSEC_PER_SEC * IPV4_ACD_PROBE_MIN;
176 			} else {
177 				delay = MSEC_PER_SEC * IPV4_ACD_ANNOUNCE_WAIT;
178 
179 			}
180 
181 			ifaddr->acd_timeout = sys_timepoint_calc(K_MSEC(delay));
182 
183 			break;
184 		}
185 
186 		net_if_ipv4_acd_succeeded(net_if_get_by_index(ifaddr->ifindex),
187 					  ifaddr);
188 
189 		ifaddr->acd_state = IPV4_ACD_ANNOUNCE;
190 		ifaddr->acd_count = 0;
191 		__fallthrough;
192 	case IPV4_ACD_ANNOUNCE:
193 		if (ifaddr->acd_count < IPV4_ACD_ANNOUNCE_NUM) {
194 			NET_DBG("Sending announcement for %s",
195 				net_sprint_ipv4_addr(&ifaddr->address.in_addr));
196 
197 			ipv4_acd_send_announcement(ifaddr);
198 
199 			ifaddr->acd_count++;
200 			ifaddr->acd_timeout = sys_timepoint_calc(
201 					K_SECONDS(IPV4_ACD_ANNOUNCE_INTERVAL));
202 
203 			break;
204 		}
205 
206 		NET_DBG("IPv4 conflict detection done for %s",
207 			net_sprint_ipv4_addr(&ifaddr->address.in_addr));
208 
209 		/* Timeout will be used to determine whether DEFEND_INTERVAL
210 		 * has expired in case of conflicts.
211 		 */
212 		ifaddr->acd_timeout = sys_timepoint_calc(K_NO_WAIT);
213 
214 		sys_slist_find_and_remove(&active_acd_timers, &ifaddr->acd_node);
215 		break;
216 	default:
217 		break;
218 	}
219 }
220 
ipv4_acd_timeout(struct k_work * work)221 static void ipv4_acd_timeout(struct k_work *work)
222 {
223 	sys_snode_t *current, *next;
224 
225 	ARG_UNUSED(work);
226 
227 	k_mutex_lock(&lock, K_FOREVER);
228 
229 	SYS_SLIST_FOR_EACH_NODE_SAFE(&active_acd_timers, current, next) {
230 		struct net_if_addr *ifaddr =
231 			CONTAINER_OF(current, struct net_if_addr, acd_node);
232 
233 		if (sys_timepoint_expired(ifaddr->acd_timeout)) {
234 			ipv4_acd_manage_timeout(ifaddr);
235 		}
236 	}
237 
238 	acd_timer_reschedule();
239 
240 	k_mutex_unlock(&lock);
241 }
242 
acd_start_timer(struct net_if * iface,struct net_if_addr * ifaddr)243 static void acd_start_timer(struct net_if *iface, struct net_if_addr *ifaddr)
244 {
245 	uint32_t delay;
246 
247 	sys_slist_find_and_remove(&active_acd_timers, &ifaddr->acd_node);
248 	sys_slist_append(&active_acd_timers, &ifaddr->acd_node);
249 
250 	if (iface->config.ip.ipv4->conflict_cnt >= IPV4_ACD_MAX_CONFLICTS) {
251 		NET_DBG("Rate limiting");
252 		delay = MSEC_PER_SEC * IPV4_ACD_RATE_LIMIT_INTERVAL;
253 	} else {
254 		/* Initial probe should be delayed by a random time interval
255 		 * between 0 and PROBE_WAIT.
256 		 */
257 		delay = sys_rand32_get() % (MSEC_PER_SEC * IPV4_ACD_PROBE_WAIT);
258 	}
259 
260 	ifaddr->acd_timeout = sys_timepoint_calc(K_MSEC(delay));
261 
262 	acd_timer_reschedule();
263 }
264 
net_ipv4_acd_input(struct net_if * iface,struct net_pkt * pkt)265 enum net_verdict net_ipv4_acd_input(struct net_if *iface, struct net_pkt *pkt)
266 {
267 	sys_snode_t *current, *next;
268 	struct net_arp_hdr *arp_hdr;
269 	struct net_if_ipv4 *ipv4;
270 
271 	if (net_pkt_get_len(pkt) < sizeof(struct net_arp_hdr)) {
272 		NET_DBG("Invalid ARP header (len %zu, min %zu bytes)",
273 			net_pkt_get_len(pkt), sizeof(struct net_arp_hdr));
274 		return NET_DROP;
275 	}
276 
277 	arp_hdr = NET_ARP_HDR(pkt);
278 
279 	k_mutex_lock(&lock, K_FOREVER);
280 
281 	SYS_SLIST_FOR_EACH_NODE_SAFE(&active_acd_timers, current, next) {
282 		struct net_if_addr *ifaddr =
283 			CONTAINER_OF(current, struct net_if_addr, acd_node);
284 		struct net_if *addr_iface = net_if_get_by_index(ifaddr->ifindex);
285 		struct net_linkaddr *ll_addr;
286 
287 		if (iface != addr_iface) {
288 			continue;
289 		}
290 
291 		if (ifaddr->acd_state != IPV4_ACD_PROBE) {
292 			continue;
293 		}
294 
295 		ll_addr = net_if_get_link_addr(addr_iface);
296 
297 		/* RFC 5227, ch. 2.1.1 Probe Details:
298 		 * - ARP Request/Reply with Sender IP address match OR,
299 		 * - ARP Probe where Target IP address match with different sender HW address,
300 		 * indicate a conflict.
301 		 * ARP Probe has an all-zero sender IP address
302 		 */
303 		if (net_ipv4_addr_cmp_raw(arp_hdr->src_ipaddr,
304 					  (uint8_t *)&ifaddr->address.in_addr) ||
305 		    (net_ipv4_addr_cmp_raw(arp_hdr->dst_ipaddr,
306 					  (uint8_t *)&ifaddr->address.in_addr) &&
307 				 (memcmp(&arp_hdr->src_hwaddr, ll_addr->addr, ll_addr->len) != 0) &&
308 				 (net_ipv4_addr_cmp_raw(arp_hdr->src_ipaddr,
309 						(uint8_t *)&(struct in_addr)INADDR_ANY_INIT)))) {
310 			NET_DBG("Conflict detected from %s for %s",
311 				net_sprint_ll_addr((uint8_t *)&arp_hdr->src_hwaddr,
312 						   arp_hdr->hwlen),
313 				net_sprint_ipv4_addr(&ifaddr->address.in_addr));
314 
315 			iface->config.ip.ipv4->conflict_cnt++;
316 
317 			net_if_ipv4_acd_failed(addr_iface, ifaddr);
318 
319 			k_mutex_unlock(&lock);
320 
321 			return NET_DROP;
322 		}
323 	}
324 
325 	k_mutex_unlock(&lock);
326 
327 	ipv4 = iface->config.ip.ipv4;
328 	if (ipv4 == NULL) {
329 		goto out;
330 	}
331 
332 	/* Passive conflict detection - try to defend already confirmed
333 	 * addresses.
334 	 */
335 	ARRAY_FOR_EACH(ipv4->unicast, i) {
336 		struct net_if_addr *ifaddr = &ipv4->unicast[i].ipv4;
337 		struct net_linkaddr *ll_addr = net_if_get_link_addr(iface);
338 
339 		if (!ifaddr->is_used) {
340 			continue;
341 		}
342 
343 		if (net_ipv4_addr_cmp_raw(arp_hdr->src_ipaddr,
344 					  (uint8_t *)&ifaddr->address.in_addr) &&
345 		    memcmp(&arp_hdr->src_hwaddr, ll_addr->addr, ll_addr->len) != 0) {
346 			NET_DBG("Conflict detected from %s for %s",
347 				net_sprint_ll_addr((uint8_t *)&arp_hdr->src_hwaddr,
348 						   arp_hdr->hwlen),
349 				net_sprint_ipv4_addr(&ifaddr->address.in_addr));
350 
351 			ipv4->conflict_cnt++;
352 
353 			/* In case timer has expired, we're past DEFEND_INTERVAL
354 			 * and can try to defend again
355 			 */
356 			if (sys_timepoint_expired(ifaddr->acd_timeout)) {
357 				NET_DBG("Defending address %s",
358 					net_sprint_ipv4_addr(&ifaddr->address.in_addr));
359 				ipv4_acd_send_announcement(ifaddr);
360 				ifaddr->acd_timeout = sys_timepoint_calc(
361 					K_SECONDS(IPV4_ACD_DEFEND_INTERVAL));
362 			} else {
363 				NET_DBG("Reporting conflict on %s",
364 					net_sprint_ipv4_addr(&ifaddr->address.in_addr));
365 				/* Otherwise report the conflict and let the
366 				 * application decide.
367 				 */
368 				net_mgmt_event_notify_with_info(
369 					NET_EVENT_IPV4_ACD_CONFLICT, iface,
370 					&ifaddr->address.in_addr,
371 					sizeof(struct in_addr));
372 			}
373 
374 			break;
375 		}
376 	}
377 
378 out:
379 	return NET_CONTINUE;
380 }
381 
net_ipv4_acd_init(void)382 void net_ipv4_acd_init(void)
383 {
384 	k_work_init_delayable(&ipv4_acd_timer, ipv4_acd_timeout);
385 }
386 
net_ipv4_acd_start(struct net_if * iface,struct net_if_addr * ifaddr)387 int net_ipv4_acd_start(struct net_if *iface, struct net_if_addr *ifaddr)
388 {
389 	/* Address conflict detection is based on ARP, so can only be done on
390 	 * supporting interfaces.
391 	 */
392 	if (!(net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET) ||
393 	      net_eth_is_vlan_interface(iface))) {
394 		net_if_ipv4_acd_succeeded(iface, ifaddr);
395 		return 0;
396 	}
397 
398 	k_mutex_lock(&lock, K_FOREVER);
399 
400 	ifaddr->ifindex = net_if_get_by_iface(iface);
401 	ifaddr->acd_state = IPV4_ACD_PROBE;
402 	ifaddr->acd_count = 0;
403 
404 	acd_start_timer(iface, ifaddr);
405 
406 	k_mutex_unlock(&lock);
407 
408 	return 0;
409 }
410 
net_ipv4_acd_cancel(struct net_if * iface,struct net_if_addr * ifaddr)411 void net_ipv4_acd_cancel(struct net_if *iface, struct net_if_addr *ifaddr)
412 {
413 	/* Address conflict detection is based on ARP, so can only be done on
414 	 * supporting interfaces.
415 	 */
416 	if (!(net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET) ||
417 	      net_eth_is_vlan_interface(iface))) {
418 		return;
419 	}
420 
421 	k_mutex_lock(&lock, K_FOREVER);
422 
423 	sys_slist_find_and_remove(&active_acd_timers, &ifaddr->acd_node);
424 	acd_timer_reschedule();
425 
426 	k_mutex_unlock(&lock);
427 }
428