Skip to content

Commit 1a5e13a

Browse files
jukkarfabiobaltieri
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 196782e commit 1a5e13a

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
@@ -112,6 +112,9 @@ struct net_if_addr {
112112
/** Address conflict detection (ACD) timer. */
113113
sys_snode_t acd_node;
114114

115+
/** ACD needed list node */
116+
sys_snode_t acd_need_node;
117+
115118
/** ACD timeout value. */
116119
k_timepoint_t acd_timeout;
117120

subsys/net/ip/net_if.c

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

43114311
void net_if_start_acd(struct net_if *iface)
43124312
{
4313+
struct net_if_addr *ifaddr, *next;
43134314
struct net_if_ipv4 *ipv4;
4315+
sys_slist_t acd_needed;
43144316
int ret;
43154317

43164318
net_if_lock(iface);
@@ -4332,6 +4334,11 @@ void net_if_start_acd(struct net_if *iface)
43324334

43334335
ipv4->conflict_cnt = 0;
43344336

4337+
/* Start ACD for all the addresses that were added earlier when
4338+
* the interface was down.
4339+
*/
4340+
sys_slist_init(&acd_needed);
4341+
43354342
/* Start ACD for all the addresses that were added earlier when
43364343
* the interface was down.
43374344
*/
@@ -4343,9 +4350,21 @@ void net_if_start_acd(struct net_if *iface)
43434350
continue;
43444351
}
43454352

4346-
net_if_ipv4_start_acd(iface, &ipv4->unicast[i].ipv4);
4353+
sys_slist_prepend(&acd_needed, &ipv4->unicast[i].ipv4.acd_need_node);
4354+
}
4355+
4356+
net_if_unlock(iface);
4357+
4358+
/* Start ACD for all the addresses without holding the iface lock
4359+
* to avoid any possible mutex deadlock issues.
4360+
*/
4361+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&acd_needed,
4362+
ifaddr, next, acd_need_node) {
4363+
net_if_ipv4_start_acd(iface, ifaddr);
43474364
}
43484365

4366+
return;
4367+
43494368
out:
43504369
net_if_unlock(iface);
43514370
}
@@ -4439,7 +4458,8 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
44394458

44404459
if (!(l2_flags_get(iface) & NET_L2_POINT_TO_POINT) &&
44414460
!net_ipv4_is_addr_loopback(addr)) {
4442-
net_if_ipv4_start_acd(iface, ifaddr);
4461+
/* ACD is started after the lock is released. */
4462+
;
44434463
} else {
44444464
ifaddr->addr_state = NET_ADDR_PREFERRED;
44454465
}
@@ -4449,7 +4469,12 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
44494469
net_mgmt_event_notify_with_info(NET_EVENT_IPV4_ADDR_ADD, iface,
44504470
&ifaddr->address.in_addr,
44514471
sizeof(struct in_addr));
4452-
goto out;
4472+
4473+
net_if_unlock(iface);
4474+
4475+
net_if_ipv4_start_acd(iface, ifaddr);
4476+
4477+
return ifaddr;
44534478
}
44544479

44554480
out:

0 commit comments

Comments
 (0)