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

net: if: Release the interface lock early when starting IPv6 DAD

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.

Signed-off-by: default avatarJukka Rissanen <jukka.rissanen@nordicsemi.no>
parent 4926698b
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
@@ -97,6 +97,9 @@ struct net_if_addr {
			/** Duplicate address detection (DAD) timer */
			sys_snode_t dad_node;

			/** DAD needed list node */
			sys_snode_t dad_need_node;

			/** DAD start time */
			uint32_t dad_start;

+31 −5
Changes for subsys/net/ip/net_if.c: 31 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -1327,8 +1327,9 @@ void net_if_ipv6_start_dad(struct net_if *iface,

void net_if_start_dad(struct net_if *iface)
{
	struct net_if_addr *ifaddr;
	struct net_if_addr *ifaddr, *next;
	struct net_if_ipv6 *ipv6;
	sys_slist_t dad_needed;
	struct in6_addr addr = { };
	int ret;

@@ -1378,6 +1379,8 @@ void net_if_start_dad(struct net_if *iface)
	/* Start DAD for all the addresses that were added earlier when
	 * the interface was down.
	 */
	sys_slist_init(&dad_needed);

	ARRAY_FOR_EACH(ipv6->unicast, i) {
		if (!ipv6->unicast[i].is_used ||
		    ipv6->unicast[i].address.family != AF_INET6 ||
@@ -1387,9 +1390,21 @@ void net_if_start_dad(struct net_if *iface)
			continue;
		}

		net_if_ipv6_start_dad(iface, &ipv6->unicast[i]);
		sys_slist_prepend(&dad_needed, &ipv6->unicast[i].dad_need_node);
	}

	net_if_unlock(iface);

	/* Start DAD for all the addresses without holding the iface lock
	 * to avoid any possible mutex deadlock issues.
	 */
	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&dad_needed,
					  ifaddr, next, dad_need_node) {
		net_if_ipv6_start_dad(iface, ifaddr);
	}

	return;

out:
	net_if_unlock(iface);
}
@@ -1437,7 +1452,10 @@ void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr)
	net_if_ipv6_addr_rm(iface, addr);

	if (IS_ENABLED(CONFIG_NET_IPV6_PE) && iface->pe_enabled) {
		net_if_unlock(iface);

		net_ipv6_pe_start(iface, addr, timeout, preferred_lifetime);
		return;
	}

out:
@@ -1966,6 +1984,7 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
{
	struct net_if_addr *ifaddr = NULL;
	struct net_if_ipv6 *ipv6;
	bool do_dad = false;

	net_if_lock(iface);

@@ -2017,8 +2036,7 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
			 */
			join_mcast_nodes(iface,
					 &ipv6->unicast[i].address.in6_addr);

			net_if_ipv6_start_dad(iface, &ipv6->unicast[i]);
			do_dad = true;
		} else {
			/* If DAD is not done for point-to-point links, then
			 * the address is usable immediately.
@@ -2032,9 +2050,17 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
			sizeof(struct in6_addr));

		ifaddr = &ipv6->unicast[i];
		goto out;
		break;
	}

	net_if_unlock(iface);

	if (ifaddr != NULL && do_dad) {
		net_if_ipv6_start_dad(iface, ifaddr);
	}

	return ifaddr;

out:
	net_if_unlock(iface);