2 * Backported from upstream commit a72a5e2d34ec
3 * ("inet: kill unused skb_free op")
5 * IPv6 fragment reassembly
6 * Linux INET6 implementation
9 * Pedro Roque <roque@di.fc.ul.pt>
11 * Based on: net/ipv4/ip_fragment.c
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
21 * Andi Kleen Make it work with multiple hosts.
22 * More RFC compliance.
24 * Horst von Brand Add missing #include <linux/string.h>
25 * Alexey Kuznetsov SMP races, threading, cleanup.
26 * Patrick McHardy LRU queue of frag heads for evictor.
27 * Mitsuru KANDA @USAGI Register inet6_protocol{}.
29 * YOSHIFUJI,H. @USAGI Always remove fragment header to
30 * calculate ICV correctly.
33 #define pr_fmt(fmt) "IPv6: " fmt
35 #if defined(OVS_FRAGMENT_BACKPORT) && \
36 LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0)
38 #include <linux/errno.h>
39 #include <linux/types.h>
40 #include <linux/string.h>
41 #include <linux/socket.h>
42 #include <linux/sockios.h>
43 #include <linux/jiffies.h>
44 #include <linux/net.h>
45 #include <linux/list.h>
46 #include <linux/netdevice.h>
47 #include <linux/in6.h>
48 #include <linux/ipv6.h>
49 #include <linux/icmpv6.h>
50 #include <linux/random.h>
51 #include <linux/jhash.h>
52 #include <linux/skbuff.h>
53 #include <linux/slab.h>
54 #include <linux/export.h>
60 #include <net/ip6_route.h>
61 #include <net/protocol.h>
62 #include <net/transp_v6.h>
63 #include <net/rawv6.h>
64 #include <net/ndisc.h>
65 #include <net/addrconf.h>
66 #include <net/inet_frag.h>
67 #include <net/inet_ecn.h>
69 void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq,
70 struct inet_frags *frags)
72 struct net_device *dev = NULL;
74 spin_lock(&fq->q.lock);
76 if (qp_flags(fq) & INET_FRAG_COMPLETE)
79 inet_frag_kill(&fq->q, frags);
82 dev = dev_get_by_index_rcu(net, fq->iif);
86 IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
88 if (inet_frag_evicting(&fq->q))
91 IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);
93 /* Don't send error if the first segment did not arrive. */
94 if (!(qp_flags(fq) & INET_FRAG_FIRST_IN) || !fq->q.fragments)
97 /* But use as source device on which LAST ARRIVED
98 * segment was received. And do not use fq->dev
99 * pointer directly, device might already disappeared.
101 fq->q.fragments->dev = dev;
102 icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0);
106 spin_unlock(&fq->q.lock);
107 inet_frag_put(&fq->q, frags);
110 #endif /* OVS_FRAGMENT_BACKPORT */