forked from Minki/linux
ipv6: distinguish frag queues by device for multicast and link-local packets
If a fragmented multicast packet is received on an ethernet device which has an active macvlan on top of it, each fragment is duplicated and received both on the underlying device and the macvlan. If some fragments for macvlan are processed before the whole packet for the underlying device is reassembled, the "overlapping fragments" test in ip6_frag_queue() discards the whole fragment queue. To resolve this, add device ifindex to the search key and require it to match reassembling multicast packets and packets to link-local addresses. Note: similar patch has been already submitted by Yoshifuji Hideaki in http://patchwork.ozlabs.org/patch/220979/ but got lost and forgotten for some reason. Signed-off-by: Michal Kubecek <mkubecek@suse.cz> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
aeb20b6b3f
commit
264640fc2c
@ -490,6 +490,7 @@ struct ip6_create_arg {
|
|||||||
u32 user;
|
u32 user;
|
||||||
const struct in6_addr *src;
|
const struct in6_addr *src;
|
||||||
const struct in6_addr *dst;
|
const struct in6_addr *dst;
|
||||||
|
int iif;
|
||||||
u8 ecn;
|
u8 ecn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ static void nf_ct_frag6_expire(unsigned long data)
|
|||||||
/* Creation primitives. */
|
/* Creation primitives. */
|
||||||
static inline struct frag_queue *fq_find(struct net *net, __be32 id,
|
static inline struct frag_queue *fq_find(struct net *net, __be32 id,
|
||||||
u32 user, struct in6_addr *src,
|
u32 user, struct in6_addr *src,
|
||||||
struct in6_addr *dst, u8 ecn)
|
struct in6_addr *dst, int iif, u8 ecn)
|
||||||
{
|
{
|
||||||
struct inet_frag_queue *q;
|
struct inet_frag_queue *q;
|
||||||
struct ip6_create_arg arg;
|
struct ip6_create_arg arg;
|
||||||
@ -200,6 +200,7 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id,
|
|||||||
arg.user = user;
|
arg.user = user;
|
||||||
arg.src = src;
|
arg.src = src;
|
||||||
arg.dst = dst;
|
arg.dst = dst;
|
||||||
|
arg.iif = iif;
|
||||||
arg.ecn = ecn;
|
arg.ecn = ecn;
|
||||||
|
|
||||||
local_bh_disable();
|
local_bh_disable();
|
||||||
@ -601,7 +602,7 @@ struct sk_buff *nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 use
|
|||||||
fhdr = (struct frag_hdr *)skb_transport_header(clone);
|
fhdr = (struct frag_hdr *)skb_transport_header(clone);
|
||||||
|
|
||||||
fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr,
|
fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr,
|
||||||
ip6_frag_ecn(hdr));
|
skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr));
|
||||||
if (fq == NULL) {
|
if (fq == NULL) {
|
||||||
pr_debug("Can't find and can't create new queue\n");
|
pr_debug("Can't find and can't create new queue\n");
|
||||||
goto ret_orig;
|
goto ret_orig;
|
||||||
|
@ -108,7 +108,10 @@ bool ip6_frag_match(const struct inet_frag_queue *q, const void *a)
|
|||||||
return fq->id == arg->id &&
|
return fq->id == arg->id &&
|
||||||
fq->user == arg->user &&
|
fq->user == arg->user &&
|
||||||
ipv6_addr_equal(&fq->saddr, arg->src) &&
|
ipv6_addr_equal(&fq->saddr, arg->src) &&
|
||||||
ipv6_addr_equal(&fq->daddr, arg->dst);
|
ipv6_addr_equal(&fq->daddr, arg->dst) &&
|
||||||
|
(arg->iif == fq->iif ||
|
||||||
|
!(ipv6_addr_type(arg->dst) & (IPV6_ADDR_MULTICAST |
|
||||||
|
IPV6_ADDR_LINKLOCAL)));
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ip6_frag_match);
|
EXPORT_SYMBOL(ip6_frag_match);
|
||||||
|
|
||||||
@ -180,7 +183,7 @@ static void ip6_frag_expire(unsigned long data)
|
|||||||
|
|
||||||
static struct frag_queue *
|
static struct frag_queue *
|
||||||
fq_find(struct net *net, __be32 id, const struct in6_addr *src,
|
fq_find(struct net *net, __be32 id, const struct in6_addr *src,
|
||||||
const struct in6_addr *dst, u8 ecn)
|
const struct in6_addr *dst, int iif, u8 ecn)
|
||||||
{
|
{
|
||||||
struct inet_frag_queue *q;
|
struct inet_frag_queue *q;
|
||||||
struct ip6_create_arg arg;
|
struct ip6_create_arg arg;
|
||||||
@ -190,6 +193,7 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src,
|
|||||||
arg.user = IP6_DEFRAG_LOCAL_DELIVER;
|
arg.user = IP6_DEFRAG_LOCAL_DELIVER;
|
||||||
arg.src = src;
|
arg.src = src;
|
||||||
arg.dst = dst;
|
arg.dst = dst;
|
||||||
|
arg.iif = iif;
|
||||||
arg.ecn = ecn;
|
arg.ecn = ecn;
|
||||||
|
|
||||||
hash = inet6_hash_frag(id, src, dst);
|
hash = inet6_hash_frag(id, src, dst);
|
||||||
@ -551,7 +555,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr,
|
fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr,
|
||||||
ip6_frag_ecn(hdr));
|
skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr));
|
||||||
if (fq) {
|
if (fq) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user