Skip to content

Commit 1ab995a

Browse files
jukkarnashif
authored andcommitted
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: Jukka Rissanen <[email protected]>
1 parent 9d55a60 commit 1ab995a

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

include/zephyr/net/net_if.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ struct net_if_addr {
9393
/** Duplicate address detection (DAD) timer */
9494
sys_snode_t dad_node;
9595

96+
/** DAD needed list node */
97+
sys_snode_t dad_need_node;
98+
9699
/** DAD start time */
97100
uint32_t dad_start;
98101

subsys/net/ip/net_if.c

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,8 +1298,9 @@ void net_if_ipv6_start_dad(struct net_if *iface,
12981298

12991299
void net_if_start_dad(struct net_if *iface)
13001300
{
1301-
struct net_if_addr *ifaddr;
1301+
struct net_if_addr *ifaddr, *next;
13021302
struct net_if_ipv6 *ipv6;
1303+
sys_slist_t dad_needed;
13031304
struct in6_addr addr = { };
13041305
int ret;
13051306

@@ -1331,6 +1332,8 @@ void net_if_start_dad(struct net_if *iface)
13311332
/* Start DAD for all the addresses that were added earlier when
13321333
* the interface was down.
13331334
*/
1335+
sys_slist_init(&dad_needed);
1336+
13341337
ARRAY_FOR_EACH(ipv6->unicast, i) {
13351338
if (!ipv6->unicast[i].is_used ||
13361339
ipv6->unicast[i].address.family != AF_INET6 ||
@@ -1340,9 +1343,21 @@ void net_if_start_dad(struct net_if *iface)
13401343
continue;
13411344
}
13421345

1343-
net_if_ipv6_start_dad(iface, &ipv6->unicast[i]);
1346+
sys_slist_prepend(&dad_needed, &ipv6->unicast[i].dad_need_node);
13441347
}
13451348

1349+
net_if_unlock(iface);
1350+
1351+
/* Start DAD for all the addresses without holding the iface lock
1352+
* to avoid any possible mutex deadlock issues.
1353+
*/
1354+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&dad_needed,
1355+
ifaddr, next, dad_need_node) {
1356+
net_if_ipv6_start_dad(iface, ifaddr);
1357+
}
1358+
1359+
return;
1360+
13461361
out:
13471362
net_if_unlock(iface);
13481363
}
@@ -1389,7 +1404,10 @@ void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr)
13891404
net_if_ipv6_addr_rm(iface, addr);
13901405

13911406
if (IS_ENABLED(CONFIG_NET_IPV6_PE) && iface->pe_enabled) {
1407+
net_if_unlock(iface);
1408+
13921409
net_ipv6_pe_start(iface, addr, timeout, preferred_lifetime);
1410+
return;
13931411
}
13941412

13951413
out:
@@ -1905,6 +1923,7 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
19051923
{
19061924
struct net_if_addr *ifaddr = NULL;
19071925
struct net_if_ipv6 *ipv6;
1926+
bool do_dad = false;
19081927

19091928
net_if_lock(iface);
19101929

@@ -1956,8 +1975,7 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
19561975
*/
19571976
join_mcast_nodes(iface,
19581977
&ipv6->unicast[i].address.in6_addr);
1959-
1960-
net_if_ipv6_start_dad(iface, &ipv6->unicast[i]);
1978+
do_dad = true;
19611979
} else {
19621980
/* If DAD is not done for point-to-point links, then
19631981
* the address is usable immediately.
@@ -1971,9 +1989,17 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
19711989
sizeof(struct in6_addr));
19721990

19731991
ifaddr = &ipv6->unicast[i];
1974-
goto out;
1992+
break;
19751993
}
19761994

1995+
net_if_unlock(iface);
1996+
1997+
if (ifaddr != NULL && do_dad) {
1998+
net_if_ipv6_start_dad(iface, ifaddr);
1999+
}
2000+
2001+
return ifaddr;
2002+
19772003
out:
19782004
net_if_unlock(iface);
19792005

0 commit comments

Comments
 (0)