Skip to content

Commit 3e86312

Browse files
committed
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: Jukka Rissanen <[email protected]>
1 parent 2c2f77d commit 3e86312

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

include/zephyr/net/net_if.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ struct net_if_addr {
110110
/** Address conflict detection (ACD) timer. */
111111
sys_snode_t acd_node;
112112

113+
/** ACD needed list node */
114+
sys_snode_t acd_need_node;
115+
113116
/** ACD timeout value. */
114117
k_timepoint_t acd_timeout;
115118

subsys/net/ip/net_if.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4208,7 +4208,9 @@ void net_if_ipv4_start_acd(struct net_if *iface, struct net_if_addr *ifaddr)
42084208

42094209
void net_if_start_acd(struct net_if *iface)
42104210
{
4211+
struct net_if_addr *ifaddr, *next;
42114212
struct net_if_ipv4 *ipv4;
4213+
sys_slist_t acd_needed;
42124214
int ret;
42134215

42144216
net_if_lock(iface);
@@ -4230,6 +4232,11 @@ void net_if_start_acd(struct net_if *iface)
42304232

42314233
ipv4->conflict_cnt = 0;
42324234

4235+
/* Start ACD for all the addresses that were added earlier when
4236+
* the interface was down.
4237+
*/
4238+
sys_slist_init(&acd_needed);
4239+
42334240
/* Start ACD for all the addresses that were added earlier when
42344241
* the interface was down.
42354242
*/
@@ -4241,9 +4248,21 @@ void net_if_start_acd(struct net_if *iface)
42414248
continue;
42424249
}
42434250

4244-
net_if_ipv4_start_acd(iface, &ipv4->unicast[i].ipv4);
4251+
sys_slist_prepend(&acd_needed, &ipv4->unicast[i].ipv4.acd_need_node);
42454252
}
42464253

4254+
net_if_unlock(iface);
4255+
4256+
/* Start ACD for all the addresses without holding the iface lock
4257+
* to avoid any possible mutex deadlock issues.
4258+
*/
4259+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&acd_needed,
4260+
ifaddr, next, acd_need_node) {
4261+
net_if_ipv4_start_acd(iface, ifaddr);
4262+
}
4263+
4264+
return;
4265+
42474266
out:
42484267
net_if_unlock(iface);
42494268
}
@@ -4335,15 +4354,21 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
43354354

43364355
if (!(l2_flags_get(iface) & NET_L2_POINT_TO_POINT) &&
43374356
!net_ipv4_is_addr_loopback(addr)) {
4338-
net_if_ipv4_start_acd(iface, ifaddr);
4357+
/* ACD is started after the lock is released. */
4358+
;
43394359
} else {
43404360
ifaddr->addr_state = NET_ADDR_PREFERRED;
43414361
}
43424362

43434363
net_mgmt_event_notify_with_info(NET_EVENT_IPV4_ADDR_ADD, iface,
43444364
&ifaddr->address.in_addr,
43454365
sizeof(struct in_addr));
4346-
goto out;
4366+
4367+
net_if_unlock(iface);
4368+
4369+
net_if_ipv4_start_acd(iface, ifaddr);
4370+
4371+
return ifaddr;
43474372
}
43484373

43494374
out:

0 commit comments

Comments
 (0)