Commit 1a5e13a7 authored by Jukka Rissanen's avatar Jukka Rissanen Committed by Fabio Baltieri
Browse files

net: if: Release the interface lock early when starting IPv4 ACD

In order to avoid any mutex deadlocks between iface->lock and
TX lock, release the interface lock before calling a function
that will acquire TX lock. See previous commit for similar issue
in RS timer handling. So here we create a separate list of ACD
addresses that are to be started when network interface comes up
without iface->lock held.

Signed-off-by: default avatarJukka Rissanen <jukka.rissanen@nordicsemi.no>
parent 196782ed
Loading
Loading
Loading
Loading
+3 −0
Changes for include/zephyr/net/net_if.h: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -112,6 +112,9 @@ struct net_if_addr {
			/** Address conflict detection (ACD) timer. */
			sys_snode_t acd_node;

			/** ACD needed list node */
			sys_snode_t acd_need_node;

			/** ACD timeout value. */
			k_timepoint_t acd_timeout;

+28 −3
Changes for subsys/net/ip/net_if.c: 28 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -4310,7 +4310,9 @@ void net_if_ipv4_start_acd(struct net_if *iface, struct net_if_addr *ifaddr)

void net_if_start_acd(struct net_if *iface)
{
	struct net_if_addr *ifaddr, *next;
	struct net_if_ipv4 *ipv4;
	sys_slist_t acd_needed;
	int ret;

	net_if_lock(iface);
@@ -4332,6 +4334,11 @@ void net_if_start_acd(struct net_if *iface)

	ipv4->conflict_cnt = 0;

	/* Start ACD for all the addresses that were added earlier when
	 * the interface was down.
	 */
	sys_slist_init(&acd_needed);

	/* Start ACD for all the addresses that were added earlier when
	 * the interface was down.
	 */
@@ -4343,9 +4350,21 @@ void net_if_start_acd(struct net_if *iface)
			continue;
		}

		net_if_ipv4_start_acd(iface, &ipv4->unicast[i].ipv4);
		sys_slist_prepend(&acd_needed, &ipv4->unicast[i].ipv4.acd_need_node);
	}

	net_if_unlock(iface);

	/* Start ACD for all the addresses without holding the iface lock
	 * to avoid any possible mutex deadlock issues.
	 */
	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&acd_needed,
					  ifaddr, next, acd_need_node) {
		net_if_ipv4_start_acd(iface, ifaddr);
	}

	return;

out:
	net_if_unlock(iface);
}
@@ -4439,7 +4458,8 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,

		if (!(l2_flags_get(iface) & NET_L2_POINT_TO_POINT) &&
		    !net_ipv4_is_addr_loopback(addr)) {
			net_if_ipv4_start_acd(iface, ifaddr);
			/* ACD is started after the lock is released. */
			;
		} else {
			ifaddr->addr_state = NET_ADDR_PREFERRED;
		}
@@ -4449,7 +4469,12 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
		net_mgmt_event_notify_with_info(NET_EVENT_IPV4_ADDR_ADD, iface,
						&ifaddr->address.in_addr,
						sizeof(struct in_addr));
		goto out;

		net_if_unlock(iface);

		net_if_ipv4_start_acd(iface, ifaddr);

		return ifaddr;
	}

out: