@@ -155,6 +155,8 @@ extern bool ipv6_chk_mcast_addr(struct net_device *dev,
const struct in6_addr *group,
const struct in6_addr *src_addr);
+extern void ipv6_mc_resend_report(struct inet6_dev *idev);
+
/*
* identify MLD packets for MLD filter exceptions
*/
@@ -3272,6 +3272,7 @@ out:
static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
{
struct net_device *dev = ifp->idev->dev;
+ int type = ipv6_addr_type(&ifp->addr);
/*
* Configure the address for reception. Now it is valid.
@@ -3279,6 +3280,12 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
ipv6_ifa_notify(RTM_NEWADDR, ifp);
+ /* While dad is in progress mld report's source address is in6_addrany.
+ * Resend with proper ll now.
+ */
+ if (type & IPV6_ADDR_LINKLOCAL)
+ ipv6_mc_resend_report(ifp->idev);
+
/* If added prefix is link local and we are prepared to process
router advertisements, start sending router solicitations.
*/
@@ -3286,7 +3293,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
if (ipv6_accept_ra(ifp->idev) &&
ifp->idev->cnf.rtr_solicits > 0 &&
(dev->flags&IFF_LOOPBACK) == 0 &&
- (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
+ (type & IPV6_ADDR_LINKLOCAL)) {
/*
* If a host as already performed a random delay
* [...] as part of DAD [...] there is no need
@@ -1814,6 +1814,22 @@ err_out:
goto out;
}
+void ipv6_mc_resend_report(struct inet6_dev *idev)
+{
+ if (MLD_V1_SEEN(idev)) {
+ struct ifmcaddr6 *mcaddr;
+ read_lock_bh(&idev->lock);
+ for (mcaddr = idev->mc_list; mcaddr; mcaddr = mcaddr->next) {
+ if (!(mcaddr->mca_flags & MAF_NOREPORT))
+ igmp6_send(&mcaddr->mca_addr, idev->dev,
+ ICMPV6_MGM_REPORT);
+ }
+ read_unlock_bh(&idev->lock);
+ } else {
+ mld_send_report(idev, NULL);
+ }
+}
+
static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
const struct in6_addr *psfsrc)
{