Skip to content

Commit 7fb377a

Browse files
jukkarnashif
authored andcommitted
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 1ab995a commit 7fb377a

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
@@ -108,6 +108,9 @@ struct net_if_addr {
108108
/** Address conflict detection (ACD) timer. */
109109
sys_snode_t acd_node;
110110

111+
/** ACD needed list node */
112+
sys_snode_t acd_need_node;
113+
111114
/** ACD timeout value. */
112115
k_timepoint_t acd_timeout;
113116

subsys/net/ip/net_if.c

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

42454245
void net_if_start_acd(struct net_if *iface)
42464246
{
4247+
struct net_if_addr *ifaddr, *next;
42474248
struct net_if_ipv4 *ipv4;
4249+
sys_slist_t acd_needed;
42484250
int ret;
42494251

42504252
net_if_lock(iface);
@@ -4266,6 +4268,11 @@ void net_if_start_acd(struct net_if *iface)
42664268

42674269
ipv4->conflict_cnt = 0;
42684270

4271+
/* Start ACD for all the addresses that were added earlier when
4272+
* the interface was down.
4273+
*/
4274+
sys_slist_init(&acd_needed);
4275+
42694276
/* Start ACD for all the addresses that were added earlier when
42704277
* the interface was down.
42714278
*/
@@ -4277,9 +4284,21 @@ void net_if_start_acd(struct net_if *iface)
42774284
continue;
42784285
}
42794286

4280-
net_if_ipv4_start_acd(iface, &ipv4->unicast[i].ipv4);
4287+
sys_slist_prepend(&acd_needed, &ipv4->unicast[i].ipv4.acd_need_node);
42814288
}
42824289

4290+
net_if_unlock(iface);
4291+
4292+
/* Start ACD for all the addresses without holding the iface lock
4293+
* to avoid any possible mutex deadlock issues.
4294+
*/
4295+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&acd_needed,
4296+
ifaddr, next, acd_need_node) {
4297+
net_if_ipv4_start_acd(iface, ifaddr);
4298+
}
4299+
4300+
return;
4301+
42834302
out:
42844303
net_if_unlock(iface);
42854304
}
@@ -4371,15 +4390,21 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
43714390

43724391
if (!(l2_flags_get(iface) & NET_L2_POINT_TO_POINT) &&
43734392
!net_ipv4_is_addr_loopback(addr)) {
4374-
net_if_ipv4_start_acd(iface, ifaddr);
4393+
/* ACD is started after the lock is released. */
4394+
;
43754395
} else {
43764396
ifaddr->addr_state = NET_ADDR_PREFERRED;
43774397
}
43784398

43794399
net_mgmt_event_notify_with_info(NET_EVENT_IPV4_ADDR_ADD, iface,
43804400
&ifaddr->address.in_addr,
43814401
sizeof(struct in_addr));
4382-
goto out;
4402+
4403+
net_if_unlock(iface);
4404+
4405+
net_if_ipv4_start_acd(iface, ifaddr);
4406+
4407+
return ifaddr;
43834408
}
43844409

43854410
out:

0 commit comments

Comments
 (0)