|
@@ -1665,7 +1665,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
|
|
skb_tailroom(skb)) : 0)
|
|
skb_tailroom(skb)) : 0)
|
|
|
|
|
|
static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
|
|
static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
|
|
- int type, int gdeleted, int sdeleted)
|
|
|
|
|
|
+ int type, int gdeleted, int sdeleted, int crsend)
|
|
{
|
|
{
|
|
struct inet6_dev *idev = pmc->idev;
|
|
struct inet6_dev *idev = pmc->idev;
|
|
struct net_device *dev = idev->dev;
|
|
struct net_device *dev = idev->dev;
|
|
@@ -1757,7 +1757,7 @@ empty_source:
|
|
if (type == MLD2_ALLOW_NEW_SOURCES ||
|
|
if (type == MLD2_ALLOW_NEW_SOURCES ||
|
|
type == MLD2_BLOCK_OLD_SOURCES)
|
|
type == MLD2_BLOCK_OLD_SOURCES)
|
|
return skb;
|
|
return skb;
|
|
- if (pmc->mca_crcount || isquery) {
|
|
|
|
|
|
+ if (pmc->mca_crcount || isquery || crsend) {
|
|
/* make sure we have room for group header */
|
|
/* make sure we have room for group header */
|
|
if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)) {
|
|
if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)) {
|
|
mld_sendpack(skb);
|
|
mld_sendpack(skb);
|
|
@@ -1789,7 +1789,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc)
|
|
type = MLD2_MODE_IS_EXCLUDE;
|
|
type = MLD2_MODE_IS_EXCLUDE;
|
|
else
|
|
else
|
|
type = MLD2_MODE_IS_INCLUDE;
|
|
type = MLD2_MODE_IS_INCLUDE;
|
|
- skb = add_grec(skb, pmc, type, 0, 0);
|
|
|
|
|
|
+ skb = add_grec(skb, pmc, type, 0, 0, 0);
|
|
spin_unlock_bh(&pmc->mca_lock);
|
|
spin_unlock_bh(&pmc->mca_lock);
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
@@ -1798,7 +1798,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc)
|
|
type = MLD2_MODE_IS_EXCLUDE;
|
|
type = MLD2_MODE_IS_EXCLUDE;
|
|
else
|
|
else
|
|
type = MLD2_MODE_IS_INCLUDE;
|
|
type = MLD2_MODE_IS_INCLUDE;
|
|
- skb = add_grec(skb, pmc, type, 0, 0);
|
|
|
|
|
|
+ skb = add_grec(skb, pmc, type, 0, 0, 0);
|
|
spin_unlock_bh(&pmc->mca_lock);
|
|
spin_unlock_bh(&pmc->mca_lock);
|
|
}
|
|
}
|
|
read_unlock_bh(&idev->lock);
|
|
read_unlock_bh(&idev->lock);
|
|
@@ -1843,13 +1843,13 @@ static void mld_send_cr(struct inet6_dev *idev)
|
|
if (pmc->mca_sfmode == MCAST_INCLUDE) {
|
|
if (pmc->mca_sfmode == MCAST_INCLUDE) {
|
|
type = MLD2_BLOCK_OLD_SOURCES;
|
|
type = MLD2_BLOCK_OLD_SOURCES;
|
|
dtype = MLD2_BLOCK_OLD_SOURCES;
|
|
dtype = MLD2_BLOCK_OLD_SOURCES;
|
|
- skb = add_grec(skb, pmc, type, 1, 0);
|
|
|
|
- skb = add_grec(skb, pmc, dtype, 1, 1);
|
|
|
|
|
|
+ skb = add_grec(skb, pmc, type, 1, 0, 0);
|
|
|
|
+ skb = add_grec(skb, pmc, dtype, 1, 1, 0);
|
|
}
|
|
}
|
|
if (pmc->mca_crcount) {
|
|
if (pmc->mca_crcount) {
|
|
if (pmc->mca_sfmode == MCAST_EXCLUDE) {
|
|
if (pmc->mca_sfmode == MCAST_EXCLUDE) {
|
|
type = MLD2_CHANGE_TO_INCLUDE;
|
|
type = MLD2_CHANGE_TO_INCLUDE;
|
|
- skb = add_grec(skb, pmc, type, 1, 0);
|
|
|
|
|
|
+ skb = add_grec(skb, pmc, type, 1, 0, 0);
|
|
}
|
|
}
|
|
pmc->mca_crcount--;
|
|
pmc->mca_crcount--;
|
|
if (pmc->mca_crcount == 0) {
|
|
if (pmc->mca_crcount == 0) {
|
|
@@ -1880,8 +1880,8 @@ static void mld_send_cr(struct inet6_dev *idev)
|
|
type = MLD2_ALLOW_NEW_SOURCES;
|
|
type = MLD2_ALLOW_NEW_SOURCES;
|
|
dtype = MLD2_BLOCK_OLD_SOURCES;
|
|
dtype = MLD2_BLOCK_OLD_SOURCES;
|
|
}
|
|
}
|
|
- skb = add_grec(skb, pmc, type, 0, 0);
|
|
|
|
- skb = add_grec(skb, pmc, dtype, 0, 1); /* deleted sources */
|
|
|
|
|
|
+ skb = add_grec(skb, pmc, type, 0, 0, 0);
|
|
|
|
+ skb = add_grec(skb, pmc, dtype, 0, 1, 0); /* deleted sources */
|
|
|
|
|
|
/* filter mode changes */
|
|
/* filter mode changes */
|
|
if (pmc->mca_crcount) {
|
|
if (pmc->mca_crcount) {
|
|
@@ -1889,7 +1889,7 @@ static void mld_send_cr(struct inet6_dev *idev)
|
|
type = MLD2_CHANGE_TO_EXCLUDE;
|
|
type = MLD2_CHANGE_TO_EXCLUDE;
|
|
else
|
|
else
|
|
type = MLD2_CHANGE_TO_INCLUDE;
|
|
type = MLD2_CHANGE_TO_INCLUDE;
|
|
- skb = add_grec(skb, pmc, type, 0, 0);
|
|
|
|
|
|
+ skb = add_grec(skb, pmc, type, 0, 0, 0);
|
|
pmc->mca_crcount--;
|
|
pmc->mca_crcount--;
|
|
}
|
|
}
|
|
spin_unlock_bh(&pmc->mca_lock);
|
|
spin_unlock_bh(&pmc->mca_lock);
|
|
@@ -1997,27 +1997,36 @@ err_out:
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
-static void mld_resend_report(struct inet6_dev *idev)
|
|
|
|
|
|
+static void mld_send_initial_cr(struct inet6_dev *idev)
|
|
{
|
|
{
|
|
- if (mld_in_v1_mode(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);
|
|
|
|
|
|
+ struct sk_buff *skb;
|
|
|
|
+ struct ifmcaddr6 *pmc;
|
|
|
|
+ int type;
|
|
|
|
+
|
|
|
|
+ if (mld_in_v1_mode(idev))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ skb = NULL;
|
|
|
|
+ read_lock_bh(&idev->lock);
|
|
|
|
+ for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
|
|
|
|
+ spin_lock_bh(&pmc->mca_lock);
|
|
|
|
+ if (pmc->mca_sfcount[MCAST_EXCLUDE])
|
|
|
|
+ type = MLD2_CHANGE_TO_EXCLUDE;
|
|
|
|
+ else
|
|
|
|
+ type = MLD2_CHANGE_TO_INCLUDE;
|
|
|
|
+ skb = add_grec(skb, pmc, type, 0, 0, 1);
|
|
|
|
+ spin_unlock_bh(&pmc->mca_lock);
|
|
}
|
|
}
|
|
|
|
+ read_unlock_bh(&idev->lock);
|
|
|
|
+ if (skb)
|
|
|
|
+ mld_sendpack(skb);
|
|
}
|
|
}
|
|
|
|
|
|
void ipv6_mc_dad_complete(struct inet6_dev *idev)
|
|
void ipv6_mc_dad_complete(struct inet6_dev *idev)
|
|
{
|
|
{
|
|
idev->mc_dad_count = idev->mc_qrv;
|
|
idev->mc_dad_count = idev->mc_qrv;
|
|
if (idev->mc_dad_count) {
|
|
if (idev->mc_dad_count) {
|
|
- mld_resend_report(idev);
|
|
|
|
|
|
+ mld_send_initial_cr(idev);
|
|
idev->mc_dad_count--;
|
|
idev->mc_dad_count--;
|
|
if (idev->mc_dad_count)
|
|
if (idev->mc_dad_count)
|
|
mld_dad_start_timer(idev, idev->mc_maxdelay);
|
|
mld_dad_start_timer(idev, idev->mc_maxdelay);
|
|
@@ -2028,7 +2037,7 @@ static void mld_dad_timer_expire(unsigned long data)
|
|
{
|
|
{
|
|
struct inet6_dev *idev = (struct inet6_dev *)data;
|
|
struct inet6_dev *idev = (struct inet6_dev *)data;
|
|
|
|
|
|
- mld_resend_report(idev);
|
|
|
|
|
|
+ mld_send_initial_cr(idev);
|
|
if (idev->mc_dad_count) {
|
|
if (idev->mc_dad_count) {
|
|
idev->mc_dad_count--;
|
|
idev->mc_dad_count--;
|
|
if (idev->mc_dad_count)
|
|
if (idev->mc_dad_count)
|