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 <jukka.rissanen@nordicsemi.no>
This commit is contained in:
parent
196782ed91
commit
1a5e13a79b
2 changed files with 31 additions and 3 deletions
|
@ -112,6 +112,9 @@ struct net_if_addr {
|
|||
/** Address conflict detection (ACD) timer. */
|
||||
sys_snode_t acd_node;
|
||||
|
||||
/** ACD needed list node */
|
||||
sys_snode_t acd_need_node;
|
||||
|
||||
/** ACD timeout value. */
|
||||
k_timepoint_t acd_timeout;
|
||||
|
||||
|
|
|
@ -4310,7 +4310,9 @@ void net_if_ipv4_start_acd(struct net_if *iface, struct net_if_addr *ifaddr)
|
|||
|
||||
void net_if_start_acd(struct net_if *iface)
|
||||
{
|
||||
struct net_if_addr *ifaddr, *next;
|
||||
struct net_if_ipv4 *ipv4;
|
||||
sys_slist_t acd_needed;
|
||||
int ret;
|
||||
|
||||
net_if_lock(iface);
|
||||
|
@ -4332,6 +4334,11 @@ void net_if_start_acd(struct net_if *iface)
|
|||
|
||||
ipv4->conflict_cnt = 0;
|
||||
|
||||
/* Start ACD for all the addresses that were added earlier when
|
||||
* the interface was down.
|
||||
*/
|
||||
sys_slist_init(&acd_needed);
|
||||
|
||||
/* Start ACD for all the addresses that were added earlier when
|
||||
* the interface was down.
|
||||
*/
|
||||
|
@ -4343,9 +4350,21 @@ void net_if_start_acd(struct net_if *iface)
|
|||
continue;
|
||||
}
|
||||
|
||||
net_if_ipv4_start_acd(iface, &ipv4->unicast[i].ipv4);
|
||||
sys_slist_prepend(&acd_needed, &ipv4->unicast[i].ipv4.acd_need_node);
|
||||
}
|
||||
|
||||
net_if_unlock(iface);
|
||||
|
||||
/* Start ACD for all the addresses without holding the iface lock
|
||||
* to avoid any possible mutex deadlock issues.
|
||||
*/
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&acd_needed,
|
||||
ifaddr, next, acd_need_node) {
|
||||
net_if_ipv4_start_acd(iface, ifaddr);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
out:
|
||||
net_if_unlock(iface);
|
||||
}
|
||||
|
@ -4439,7 +4458,8 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
|
|||
|
||||
if (!(l2_flags_get(iface) & NET_L2_POINT_TO_POINT) &&
|
||||
!net_ipv4_is_addr_loopback(addr)) {
|
||||
net_if_ipv4_start_acd(iface, ifaddr);
|
||||
/* ACD is started after the lock is released. */
|
||||
;
|
||||
} else {
|
||||
ifaddr->addr_state = NET_ADDR_PREFERRED;
|
||||
}
|
||||
|
@ -4449,7 +4469,12 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
|
|||
net_mgmt_event_notify_with_info(NET_EVENT_IPV4_ADDR_ADD, iface,
|
||||
&ifaddr->address.in_addr,
|
||||
sizeof(struct in_addr));
|
||||
goto out;
|
||||
|
||||
net_if_unlock(iface);
|
||||
|
||||
net_if_ipv4_start_acd(iface, ifaddr);
|
||||
|
||||
return ifaddr;
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue