diff options
Diffstat (limited to 'net/ipv6/mcast.c')
-rw-r--r-- | net/ipv6/mcast.c | 57 |
1 files changed, 33 insertions, 24 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 7ff82b3e54b6..e1e47350784b 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -1665,7 +1665,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc, | |||
1665 | skb_tailroom(skb)) : 0) | 1665 | skb_tailroom(skb)) : 0) |
1666 | 1666 | ||
1667 | static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, | 1667 | static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, |
1668 | int type, int gdeleted, int sdeleted) | 1668 | int type, int gdeleted, int sdeleted, int crsend) |
1669 | { | 1669 | { |
1670 | struct inet6_dev *idev = pmc->idev; | 1670 | struct inet6_dev *idev = pmc->idev; |
1671 | struct net_device *dev = idev->dev; | 1671 | struct net_device *dev = idev->dev; |
@@ -1757,7 +1757,7 @@ empty_source: | |||
1757 | if (type == MLD2_ALLOW_NEW_SOURCES || | 1757 | if (type == MLD2_ALLOW_NEW_SOURCES || |
1758 | type == MLD2_BLOCK_OLD_SOURCES) | 1758 | type == MLD2_BLOCK_OLD_SOURCES) |
1759 | return skb; | 1759 | return skb; |
1760 | if (pmc->mca_crcount || isquery) { | 1760 | if (pmc->mca_crcount || isquery || crsend) { |
1761 | /* make sure we have room for group header */ | 1761 | /* make sure we have room for group header */ |
1762 | if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)) { | 1762 | if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)) { |
1763 | mld_sendpack(skb); | 1763 | mld_sendpack(skb); |
@@ -1789,7 +1789,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc) | |||
1789 | type = MLD2_MODE_IS_EXCLUDE; | 1789 | type = MLD2_MODE_IS_EXCLUDE; |
1790 | else | 1790 | else |
1791 | type = MLD2_MODE_IS_INCLUDE; | 1791 | type = MLD2_MODE_IS_INCLUDE; |
1792 | skb = add_grec(skb, pmc, type, 0, 0); | 1792 | skb = add_grec(skb, pmc, type, 0, 0, 0); |
1793 | spin_unlock_bh(&pmc->mca_lock); | 1793 | spin_unlock_bh(&pmc->mca_lock); |
1794 | } | 1794 | } |
1795 | } else { | 1795 | } else { |
@@ -1798,7 +1798,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc) | |||
1798 | type = MLD2_MODE_IS_EXCLUDE; | 1798 | type = MLD2_MODE_IS_EXCLUDE; |
1799 | else | 1799 | else |
1800 | type = MLD2_MODE_IS_INCLUDE; | 1800 | type = MLD2_MODE_IS_INCLUDE; |
1801 | skb = add_grec(skb, pmc, type, 0, 0); | 1801 | skb = add_grec(skb, pmc, type, 0, 0, 0); |
1802 | spin_unlock_bh(&pmc->mca_lock); | 1802 | spin_unlock_bh(&pmc->mca_lock); |
1803 | } | 1803 | } |
1804 | read_unlock_bh(&idev->lock); | 1804 | read_unlock_bh(&idev->lock); |
@@ -1843,13 +1843,13 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1843 | if (pmc->mca_sfmode == MCAST_INCLUDE) { | 1843 | if (pmc->mca_sfmode == MCAST_INCLUDE) { |
1844 | type = MLD2_BLOCK_OLD_SOURCES; | 1844 | type = MLD2_BLOCK_OLD_SOURCES; |
1845 | dtype = MLD2_BLOCK_OLD_SOURCES; | 1845 | dtype = MLD2_BLOCK_OLD_SOURCES; |
1846 | skb = add_grec(skb, pmc, type, 1, 0); | 1846 | skb = add_grec(skb, pmc, type, 1, 0, 0); |
1847 | skb = add_grec(skb, pmc, dtype, 1, 1); | 1847 | skb = add_grec(skb, pmc, dtype, 1, 1, 0); |
1848 | } | 1848 | } |
1849 | if (pmc->mca_crcount) { | 1849 | if (pmc->mca_crcount) { |
1850 | if (pmc->mca_sfmode == MCAST_EXCLUDE) { | 1850 | if (pmc->mca_sfmode == MCAST_EXCLUDE) { |
1851 | type = MLD2_CHANGE_TO_INCLUDE; | 1851 | type = MLD2_CHANGE_TO_INCLUDE; |
1852 | skb = add_grec(skb, pmc, type, 1, 0); | 1852 | skb = add_grec(skb, pmc, type, 1, 0, 0); |
1853 | } | 1853 | } |
1854 | pmc->mca_crcount--; | 1854 | pmc->mca_crcount--; |
1855 | if (pmc->mca_crcount == 0) { | 1855 | if (pmc->mca_crcount == 0) { |
@@ -1880,8 +1880,8 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1880 | type = MLD2_ALLOW_NEW_SOURCES; | 1880 | type = MLD2_ALLOW_NEW_SOURCES; |
1881 | dtype = MLD2_BLOCK_OLD_SOURCES; | 1881 | dtype = MLD2_BLOCK_OLD_SOURCES; |
1882 | } | 1882 | } |
1883 | skb = add_grec(skb, pmc, type, 0, 0); | 1883 | skb = add_grec(skb, pmc, type, 0, 0, 0); |
1884 | skb = add_grec(skb, pmc, dtype, 0, 1); /* deleted sources */ | 1884 | skb = add_grec(skb, pmc, dtype, 0, 1, 0); /* deleted sources */ |
1885 | 1885 | ||
1886 | /* filter mode changes */ | 1886 | /* filter mode changes */ |
1887 | if (pmc->mca_crcount) { | 1887 | if (pmc->mca_crcount) { |
@@ -1889,7 +1889,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1889 | type = MLD2_CHANGE_TO_EXCLUDE; | 1889 | type = MLD2_CHANGE_TO_EXCLUDE; |
1890 | else | 1890 | else |
1891 | type = MLD2_CHANGE_TO_INCLUDE; | 1891 | type = MLD2_CHANGE_TO_INCLUDE; |
1892 | skb = add_grec(skb, pmc, type, 0, 0); | 1892 | skb = add_grec(skb, pmc, type, 0, 0, 0); |
1893 | pmc->mca_crcount--; | 1893 | pmc->mca_crcount--; |
1894 | } | 1894 | } |
1895 | spin_unlock_bh(&pmc->mca_lock); | 1895 | spin_unlock_bh(&pmc->mca_lock); |
@@ -1997,27 +1997,36 @@ err_out: | |||
1997 | goto out; | 1997 | goto out; |
1998 | } | 1998 | } |
1999 | 1999 | ||
2000 | static void mld_resend_report(struct inet6_dev *idev) | 2000 | static void mld_send_initial_cr(struct inet6_dev *idev) |
2001 | { | 2001 | { |
2002 | if (mld_in_v1_mode(idev)) { | 2002 | struct sk_buff *skb; |
2003 | struct ifmcaddr6 *mcaddr; | 2003 | struct ifmcaddr6 *pmc; |
2004 | read_lock_bh(&idev->lock); | 2004 | int type; |
2005 | for (mcaddr = idev->mc_list; mcaddr; mcaddr = mcaddr->next) { | 2005 | |
2006 | if (!(mcaddr->mca_flags & MAF_NOREPORT)) | 2006 | if (mld_in_v1_mode(idev)) |
2007 | igmp6_send(&mcaddr->mca_addr, idev->dev, | 2007 | return; |
2008 | ICMPV6_MGM_REPORT); | 2008 | |
2009 | } | 2009 | skb = NULL; |
2010 | read_unlock_bh(&idev->lock); | 2010 | read_lock_bh(&idev->lock); |
2011 | } else { | 2011 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { |
2012 | mld_send_report(idev, NULL); | 2012 | spin_lock_bh(&pmc->mca_lock); |
2013 | if (pmc->mca_sfcount[MCAST_EXCLUDE]) | ||
2014 | type = MLD2_CHANGE_TO_EXCLUDE; | ||
2015 | else | ||
2016 | type = MLD2_CHANGE_TO_INCLUDE; | ||
2017 | skb = add_grec(skb, pmc, type, 0, 0, 1); | ||
2018 | spin_unlock_bh(&pmc->mca_lock); | ||
2013 | } | 2019 | } |
2020 | read_unlock_bh(&idev->lock); | ||
2021 | if (skb) | ||
2022 | mld_sendpack(skb); | ||
2014 | } | 2023 | } |
2015 | 2024 | ||
2016 | void ipv6_mc_dad_complete(struct inet6_dev *idev) | 2025 | void ipv6_mc_dad_complete(struct inet6_dev *idev) |
2017 | { | 2026 | { |
2018 | idev->mc_dad_count = idev->mc_qrv; | 2027 | idev->mc_dad_count = idev->mc_qrv; |
2019 | if (idev->mc_dad_count) { | 2028 | if (idev->mc_dad_count) { |
2020 | mld_resend_report(idev); | 2029 | mld_send_initial_cr(idev); |
2021 | idev->mc_dad_count--; | 2030 | idev->mc_dad_count--; |
2022 | if (idev->mc_dad_count) | 2031 | if (idev->mc_dad_count) |
2023 | mld_dad_start_timer(idev, idev->mc_maxdelay); | 2032 | mld_dad_start_timer(idev, idev->mc_maxdelay); |
@@ -2028,7 +2037,7 @@ static void mld_dad_timer_expire(unsigned long data) | |||
2028 | { | 2037 | { |
2029 | struct inet6_dev *idev = (struct inet6_dev *)data; | 2038 | struct inet6_dev *idev = (struct inet6_dev *)data; |
2030 | 2039 | ||
2031 | mld_resend_report(idev); | 2040 | mld_send_initial_cr(idev); |
2032 | if (idev->mc_dad_count) { | 2041 | if (idev->mc_dad_count) { |
2033 | idev->mc_dad_count--; | 2042 | idev->mc_dad_count--; |
2034 | if (idev->mc_dad_count) | 2043 | if (idev->mc_dad_count) |