Skip to content

Commit 196782e

Browse files
jukkarfabiobaltieri
authored andcommitted
net: if: Release the interface lock early when rejoining mcast groups
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 multicast addresses that are to be rejoined when network interface comes up and then rejoin the groups without iface->lock held. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 1e88c62 commit 196782e

File tree

2 files changed

+54
-22
lines changed

2 files changed

+54
-22
lines changed

include/zephyr/net/net_if.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ struct net_if_mcast_addr {
158158
/** IP address */
159159
struct net_addr address;
160160

161+
/** Rejoining multicast groups list node */
162+
sys_snode_t rejoin_node;
163+
161164
#if defined(CONFIG_NET_IPV4_IGMPV3)
162165
/** Sources to filter on */
163166
struct net_addr sources[CONFIG_NET_IF_MCAST_IPV4_SOURCE_COUNT];

subsys/net/ip/net_if.c

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,7 +1641,9 @@ void net_if_nbr_reachability_hint(struct net_if *iface, const struct in6_addr *i
16411641
*/
16421642
static void rejoin_ipv6_mcast_groups(struct net_if *iface)
16431643
{
1644+
struct net_if_mcast_addr *ifaddr, *next;
16441645
struct net_if_ipv6 *ipv6;
1646+
sys_slist_t rejoin_needed;
16451647

16461648
net_if_lock(iface);
16471649

@@ -1663,27 +1665,41 @@ static void rejoin_ipv6_mcast_groups(struct net_if *iface)
16631665
join_mcast_nodes(iface, &ipv6->unicast[i].address.in6_addr);
16641666
}
16651667

1668+
sys_slist_init(&rejoin_needed);
1669+
16661670
/* Rejoin any mcast address present on the interface, but marked as not joined. */
16671671
ARRAY_FOR_EACH(ipv6->mcast, i) {
1668-
int ret;
1669-
16701672
if (!ipv6->mcast[i].is_used ||
16711673
net_if_ipv6_maddr_is_joined(&ipv6->mcast[i])) {
16721674
continue;
16731675
}
16741676

1675-
ret = net_ipv6_mld_join(iface, &ipv6->mcast[i].address.in6_addr);
1677+
sys_slist_prepend(&rejoin_needed, &ipv6->mcast[i].rejoin_node);
1678+
}
1679+
1680+
net_if_unlock(iface);
1681+
1682+
/* Start DAD for all the addresses without holding the iface lock
1683+
* to avoid any possible mutex deadlock issues.
1684+
*/
1685+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&rejoin_needed,
1686+
ifaddr, next, rejoin_node) {
1687+
int ret;
1688+
1689+
ret = net_ipv6_mld_join(iface, &ifaddr->address.in6_addr);
16761690
if (ret < 0) {
16771691
NET_ERR("Cannot join mcast address %s for %d (%d)",
1678-
net_sprint_ipv6_addr(&ipv6->mcast[i].address.in6_addr),
1692+
net_sprint_ipv6_addr(&ifaddr->address.in6_addr),
16791693
net_if_get_by_iface(iface), ret);
16801694
} else {
16811695
NET_DBG("Rejoined mcast address %s for %d",
1682-
net_sprint_ipv6_addr(&ipv6->mcast[i].address.in6_addr),
1696+
net_sprint_ipv6_addr(&ifaddr->address.in6_addr),
16831697
net_if_get_by_iface(iface));
16841698
}
16851699
}
16861700

1701+
return;
1702+
16871703
out:
16881704
net_if_unlock(iface);
16891705
}
@@ -2024,18 +2040,7 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
20242040
if (!(l2_flags_get(iface) & NET_L2_POINT_TO_POINT) &&
20252041
!net_ipv6_is_addr_loopback(addr) &&
20262042
!net_if_flag_is_set(iface, NET_IF_IPV6_NO_ND)) {
2027-
/* RFC 4862 5.4.2
2028-
* Before sending a Neighbor Solicitation, an interface
2029-
* MUST join the all-nodes multicast address and the
2030-
* solicited-node multicast address of the tentative
2031-
* address.
2032-
*/
2033-
/* The allnodes multicast group is only joined once as
2034-
* net_ipv6_mld_join() checks if we have already
2035-
* joined.
2036-
*/
2037-
join_mcast_nodes(iface,
2038-
&ipv6->unicast[i].address.in6_addr);
2043+
/* The groups are joined without locks held */
20392044
do_dad = true;
20402045
} else {
20412046
/* If DAD is not done for point-to-point links, then
@@ -2056,6 +2061,18 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
20562061
net_if_unlock(iface);
20572062

20582063
if (ifaddr != NULL && do_dad) {
2064+
/* RFC 4862 5.4.2
2065+
* Before sending a Neighbor Solicitation, an interface
2066+
* MUST join the all-nodes multicast address and the
2067+
* solicited-node multicast address of the tentative
2068+
* address.
2069+
*/
2070+
/* The allnodes multicast group is only joined once as
2071+
* net_ipv6_mld_join() checks if we have already
2072+
* joined.
2073+
*/
2074+
join_mcast_nodes(iface, &ifaddr->address.in6_addr);
2075+
20592076
net_if_ipv6_start_dad(iface, ifaddr);
20602077
}
20612078

@@ -4912,7 +4929,9 @@ static void iface_ipv4_start(struct net_if *iface)
49124929
*/
49134930
static void rejoin_ipv4_mcast_groups(struct net_if *iface)
49144931
{
4932+
struct net_if_mcast_addr *ifaddr, *next;
49154933
struct net_if_ipv4 *ipv4;
4934+
sys_slist_t rejoin_needed;
49164935

49174936
net_if_lock(iface);
49184937

@@ -4924,27 +4943,37 @@ static void rejoin_ipv4_mcast_groups(struct net_if *iface)
49244943
goto out;
49254944
}
49264945

4946+
sys_slist_init(&rejoin_needed);
4947+
49274948
/* Rejoin any mcast address present on the interface, but marked as not joined. */
49284949
ARRAY_FOR_EACH(ipv4->mcast, i) {
4929-
int ret;
4930-
49314950
if (!ipv4->mcast[i].is_used ||
49324951
net_if_ipv4_maddr_is_joined(&ipv4->mcast[i])) {
49334952
continue;
49344953
}
49354954

4936-
ret = net_ipv4_igmp_join(iface, &ipv4->mcast[i].address.in_addr, NULL);
4955+
sys_slist_prepend(&rejoin_needed, &ipv4->mcast[i].rejoin_node);
4956+
}
4957+
4958+
net_if_unlock(iface);
4959+
4960+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&rejoin_needed, ifaddr, next, rejoin_node) {
4961+
int ret;
4962+
4963+
ret = net_ipv4_igmp_join(iface, &ifaddr->address.in_addr, NULL);
49374964
if (ret < 0) {
49384965
NET_ERR("Cannot join mcast address %s for %d (%d)",
4939-
net_sprint_ipv4_addr(&ipv4->mcast[i].address.in_addr),
4966+
net_sprint_ipv4_addr(&ifaddr->address.in_addr),
49404967
net_if_get_by_iface(iface), ret);
49414968
} else {
49424969
NET_DBG("Rejoined mcast address %s for %d",
4943-
net_sprint_ipv4_addr(&ipv4->mcast[i].address.in_addr),
4970+
net_sprint_ipv4_addr(&ifaddr->address.in_addr),
49444971
net_if_get_by_iface(iface));
49454972
}
49464973
}
49474974

4975+
return;
4976+
49484977
out:
49494978
net_if_unlock(iface);
49504979
}

0 commit comments

Comments
 (0)