Skip to content

Commit 078d6d5

Browse files
committed
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 9335958 commit 078d6d5

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
@@ -95,6 +95,9 @@ struct net_if_addr {
9595
/** Duplicate address detection (DAD) timer */
9696
sys_snode_t dad_node;
9797

98+
/** DAD needed list node */
99+
sys_snode_t dad_need_node;
100+
98101
/** DAD start time */
99102
uint32_t dad_start;
100103

subsys/net/ip/net_if.c

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

13251325
void net_if_start_dad(struct net_if *iface)
13261326
{
1327-
struct net_if_addr *ifaddr;
1327+
struct net_if_addr *ifaddr, *next;
13281328
struct net_if_ipv6 *ipv6;
1329+
sys_slist_t dad_needed;
13291330
struct in6_addr addr = { };
13301331
int ret;
13311332

@@ -1357,6 +1358,8 @@ void net_if_start_dad(struct net_if *iface)
13571358
/* Start DAD for all the addresses that were added earlier when
13581359
* the interface was down.
13591360
*/
1361+
sys_slist_init(&dad_needed);
1362+
13601363
ARRAY_FOR_EACH(ipv6->unicast, i) {
13611364
if (!ipv6->unicast[i].is_used ||
13621365
ipv6->unicast[i].address.family != AF_INET6 ||
@@ -1366,9 +1369,21 @@ void net_if_start_dad(struct net_if *iface)
13661369
continue;
13671370
}
13681371

1369-
net_if_ipv6_start_dad(iface, &ipv6->unicast[i]);
1372+
sys_slist_prepend(&dad_needed, &ipv6->unicast[i].dad_need_node);
13701373
}
13711374

1375+
net_if_unlock(iface);
1376+
1377+
/* Start DAD for all the addresses without holding the iface lock
1378+
* to avoid any possible mutex deadlock issues.
1379+
*/
1380+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&dad_needed,
1381+
ifaddr, next, dad_need_node) {
1382+
net_if_ipv6_start_dad(iface, ifaddr);
1383+
}
1384+
1385+
return;
1386+
13721387
out:
13731388
net_if_unlock(iface);
13741389
}
@@ -1415,7 +1430,10 @@ void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr)
14151430
net_if_ipv6_addr_rm(iface, addr);
14161431

14171432
if (IS_ENABLED(CONFIG_NET_IPV6_PE) && iface->pe_enabled) {
1433+
net_if_unlock(iface);
1434+
14181435
net_ipv6_pe_start(iface, addr, timeout, preferred_lifetime);
1436+
return;
14191437
}
14201438

14211439
out:
@@ -1944,6 +1962,7 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
19441962
{
19451963
struct net_if_addr *ifaddr = NULL;
19461964
struct net_if_ipv6 *ipv6;
1965+
bool do_dad = false;
19471966

19481967
net_if_lock(iface);
19491968

@@ -1995,8 +2014,7 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
19952014
*/
19962015
join_mcast_nodes(iface,
19972016
&ipv6->unicast[i].address.in6_addr);
1998-
1999-
net_if_ipv6_start_dad(iface, &ipv6->unicast[i]);
2017+
do_dad = true;
20002018
} else {
20012019
/* If DAD is not done for point-to-point links, then
20022020
* the address is usable immediately.
@@ -2010,9 +2028,17 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
20102028
sizeof(struct in6_addr));
20112029

20122030
ifaddr = &ipv6->unicast[i];
2013-
goto out;
2031+
break;
20142032
}
20152033

2034+
net_if_unlock(iface);
2035+
2036+
if (ifaddr != NULL && do_dad) {
2037+
net_if_ipv6_start_dad(iface, ifaddr);
2038+
}
2039+
2040+
return ifaddr;
2041+
20162042
out:
20172043
net_if_unlock(iface);
20182044

0 commit comments

Comments
 (0)