These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / ipv6 / reassembly.c
index 8ffa2c8..45f5ae5 100644 (file)
@@ -108,7 +108,10 @@ bool ip6_frag_match(const struct inet_frag_queue *q, const void *a)
        return  fq->id == arg->id &&
                fq->user == arg->user &&
                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);
 
@@ -144,7 +147,7 @@ void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq,
 
        IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
 
-       if (fq->q.flags & INET_FRAG_EVICTED)
+       if (inet_frag_evicting(&fq->q))
                goto out_rcu_unlock;
 
        IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);
@@ -180,7 +183,7 @@ static void ip6_frag_expire(unsigned long data)
 
 static struct frag_queue *
 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 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.src = src;
        arg.dst = dst;
+       arg.iif = iif;
        arg.ecn = ecn;
 
        hash = inet6_hash_frag(id, src, dst);
@@ -330,7 +334,7 @@ found:
        fq->q.stamp = skb->tstamp;
        fq->q.meat += skb->len;
        fq->ecn |= ecn;
-       add_frag_mem_limit(&fq->q, skb->truesize);
+       add_frag_mem_limit(fq->q.net, skb->truesize);
 
        /* The first fragment.
         * nhoffset is obtained from the first fragment, of course.
@@ -443,7 +447,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                head->len -= clone->len;
                clone->csum = 0;
                clone->ip_summed = head->ip_summed;
-               add_frag_mem_limit(&fq->q, clone->truesize);
+               add_frag_mem_limit(fq->q.net, clone->truesize);
        }
 
        /* We have to remove fragment header from datagram and to relocate
@@ -481,7 +485,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                }
                fp = next;
        }
-       sub_frag_mem_limit(&fq->q, sum_truesize);
+       sub_frag_mem_limit(fq->q.net, sum_truesize);
 
        head->next = NULL;
        head->dev = dev;
@@ -551,7 +555,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
        }
 
        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) {
                int ret;
 
@@ -706,13 +710,19 @@ static void ip6_frags_sysctl_unregister(void)
 
 static int __net_init ipv6_frags_init_net(struct net *net)
 {
+       int res;
+
        net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
        net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
        net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT;
 
-       inet_frags_init_net(&net->ipv6.frags);
-
-       return ip6_frags_ns_sysctl_register(net);
+       res = inet_frags_init_net(&net->ipv6.frags);
+       if (res)
+               return res;
+       res = ip6_frags_ns_sysctl_register(net);
+       if (res)
+               inet_frags_uninit_net(&net->ipv6.frags);
+       return res;
 }
 
 static void __net_exit ipv6_frags_exit_net(struct net *net)