@@ -1641,7 +1641,9 @@ void net_if_nbr_reachability_hint(struct net_if *iface, const struct in6_addr *i
16411641 */
16421642static 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+
16871703out :
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 */
49134930static 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+
49484977out :
49494978 net_if_unlock (iface );
49504979}
0 commit comments