Commit 0f052693 authored by David Stevens's avatar David Stevens Committed by David S. Miller

[IPV6]: Except MLD packets from source filtering.

Co-authored with Yoshfuji Hideaki.
parent 297aeda7
...@@ -98,6 +98,7 @@ extern void addrconf_dad_failure(struct inet6_ifaddr *ifp); ...@@ -98,6 +98,7 @@ extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);
extern int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group, extern int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group,
struct in6_addr *src_addr); struct in6_addr *src_addr);
extern int ipv6_is_mld(struct sk_buff *skb, int nexthdr);
extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len); extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len);
......
...@@ -168,11 +168,19 @@ static inline int ip6_input_finish(struct sk_buff *skb) ...@@ -168,11 +168,19 @@ static inline int ip6_input_finish(struct sk_buff *skb)
smp_read_barrier_depends(); smp_read_barrier_depends();
if (ipprot->flags & INET6_PROTO_FINAL) { if (ipprot->flags & INET6_PROTO_FINAL) {
struct ipv6hdr *hdr;
if (!cksum_sub && skb->ip_summed == CHECKSUM_HW) { if (!cksum_sub && skb->ip_summed == CHECKSUM_HW) {
skb->csum = csum_sub(skb->csum, skb->csum = csum_sub(skb->csum,
csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0)); csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
cksum_sub++; cksum_sub++;
} }
hdr = skb->nh.ipv6h;
if (ipv6_addr_is_multicast(&hdr->daddr) &&
!ipv6_chk_mcast_addr(skb->dev, &hdr->daddr,
&hdr->saddr) &&
!ipv6_is_mld(skb, nexthdr))
goto discard;
} }
if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
...@@ -211,15 +219,14 @@ int ip6_input(struct sk_buff *skb) ...@@ -211,15 +219,14 @@ int ip6_input(struct sk_buff *skb)
int ip6_mc_input(struct sk_buff *skb) int ip6_mc_input(struct sk_buff *skb)
{ {
struct ipv6hdr *hdr; struct ipv6hdr *hdr;
int deliver = 0; int deliver;
int discard = 1;
IP6_INC_STATS_BH(Ip6InMcastPkts); IP6_INC_STATS_BH(Ip6InMcastPkts);
hdr = skb->nh.ipv6h; hdr = skb->nh.ipv6h;
if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, &hdr->saddr)) deliver = likely(!(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI))) ||
deliver = 1; ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);
/* /*
* IPv6 multicast router mode isnt currently supported. * IPv6 multicast router mode isnt currently supported.
...@@ -238,23 +245,21 @@ int ip6_mc_input(struct sk_buff *skb) ...@@ -238,23 +245,21 @@ int ip6_mc_input(struct sk_buff *skb)
if (deliver) { if (deliver) {
skb2 = skb_clone(skb, GFP_ATOMIC); skb2 = skb_clone(skb, GFP_ATOMIC);
dst_output(skb2);
} else { } else {
discard = 0; dst_output(skb);
skb2 = skb; return 0;
} }
dst_output(skb2);
} }
} }
#endif #endif
if (deliver) { if (likely(deliver)) {
discard = 0;
ip6_input(skb); ip6_input(skb);
return 0;
} }
/* discard */
if (discard) kfree_skb(skb);
kfree_skb(skb);
return 0; return 0;
} }
...@@ -900,6 +900,33 @@ int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr) ...@@ -900,6 +900,33 @@ int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr)
return err; return err;
} }
/*
* identify MLD packets for MLD filter exceptions
*/
int ipv6_is_mld(struct sk_buff *skb, int nexthdr)
{
struct icmp6hdr *pic;
if (nexthdr != IPPROTO_ICMPV6)
return 0;
if (!pskb_may_pull(skb, sizeof(struct icmp6hdr)))
return 0;
pic = (struct icmp6hdr *)skb->h.raw;
switch (pic->icmp6_type) {
case ICMPV6_MGM_QUERY:
case ICMPV6_MGM_REPORT:
case ICMPV6_MGM_REDUCTION:
case ICMPV6_MLD2_REPORT:
return 1;
default:
break;
}
return 0;
}
/* /*
* check if the interface/address pair is valid * check if the interface/address pair is valid
*/ */
...@@ -918,7 +945,7 @@ int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group, ...@@ -918,7 +945,7 @@ int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group,
break; break;
} }
if (mc) { if (mc) {
if (!ipv6_addr_any(src_addr)) { if (src_addr && !ipv6_addr_any(src_addr)) {
struct ip6_sf_list *psf; struct ip6_sf_list *psf;
spin_lock_bh(&mc->mca_lock); spin_lock_bh(&mc->mca_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment