diff options
Diffstat (limited to 'net/ipv6/mcast.c')
-rw-r--r-- | net/ipv6/mcast.c | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 519899fb11d..fd939da090c 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -164,7 +164,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, #define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value)) #define MLDV2_EXP(thresh, nbmant, nbexp, value) \ ((value) < (thresh) ? (value) : \ - ((MLDV2_MASK(value, nbmant) | (1<<(nbmant+nbexp))) << \ + ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \ (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp)))) #define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value) @@ -545,8 +545,10 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) sock_kfree_s(sk, newpsl, IP6_SFLSIZE(newpsl->sl_max)); goto done; } - } else + } else { newpsl = NULL; + (void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0); + } psl = pmc->sflist; if (psl) { (void) ip6_mc_del_src(idev, group, pmc->sfmode, @@ -1087,7 +1089,7 @@ static void mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, int igmp6_event_query(struct sk_buff *skb) { - struct mld2_query *mlh2 = (struct mld2_query *) skb->h.raw; + struct mld2_query *mlh2 = NULL; struct ifmcaddr6 *ma; struct in6_addr *group; unsigned long max_delay; @@ -1140,6 +1142,13 @@ int igmp6_event_query(struct sk_buff *skb) /* clear deleted report items */ mld_clear_delrec(idev); } else if (len >= 28) { + int srcs_offset = sizeof(struct mld2_query) - + sizeof(struct icmp6hdr); + if (!pskb_may_pull(skb, srcs_offset)) { + in6_dev_put(idev); + return -EINVAL; + } + mlh2 = (struct mld2_query *) skb->h.raw; max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000; if (!max_delay) max_delay = 1; @@ -1156,7 +1165,15 @@ int igmp6_event_query(struct sk_buff *skb) return 0; } /* mark sources to include, if group & source-specific */ - mark = mlh2->nsrcs != 0; + if (mlh2->nsrcs != 0) { + if (!pskb_may_pull(skb, srcs_offset + + mlh2->nsrcs * sizeof(struct in6_addr))) { + in6_dev_put(idev); + return -EINVAL; + } + mlh2 = (struct mld2_query *) skb->h.raw; + mark = 1; + } } else { in6_dev_put(idev); return -EINVAL; @@ -1214,6 +1231,11 @@ int igmp6_event_report(struct sk_buff *skb) if (skb->pkt_type == PACKET_LOOPBACK) return 0; + /* send our report if the MC router may not have heard this report */ + if (skb->pkt_type != PACKET_MULTICAST && + skb->pkt_type != PACKET_BROADCAST) + return 0; + if (!pskb_may_pull(skb, sizeof(struct in6_addr))) return -EINVAL; @@ -1393,7 +1415,7 @@ static void mld_sendpack(struct sk_buff *skb) static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) { - return sizeof(struct mld2_grec) + 4*mld_scount(pmc,type,gdel,sdel); + return sizeof(struct mld2_grec) + 16 * mld_scount(pmc,type,gdel,sdel); } static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc, |