diff options
author | Peter Oskolkov <posk@google.com> | 2019-01-22 10:02:51 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-01-25 21:37:11 -0800 |
commit | d4289fcc9b16b89619ee1c54f829e05e56de8b9a (patch) | |
tree | c49e51dc6fb2121bdfb57e250f7962f1dae1b43a /include/net/ipv6_frag.h | |
parent | c23f35d19db3b36ffb9e04b08f1d91565d15f84f (diff) | |
download | lwn-d4289fcc9b16b89619ee1c54f829e05e56de8b9a.tar.gz lwn-d4289fcc9b16b89619ee1c54f829e05e56de8b9a.zip |
net: IP6 defrag: use rbtrees for IPv6 defrag
Currently, IPv6 defragmentation code drops non-last fragments that
are smaller than 1280 bytes: see
commit 0ed4229b08c1 ("ipv6: defrag: drop non-last frags smaller than min mtu")
This behavior is not specified in IPv6 RFCs and appears to break
compatibility with some IPv6 implemenations, as reported here:
https://www.spinics.net/lists/netdev/msg543846.html
This patch re-uses common IP defragmentation queueing and reassembly
code in IPv6, removing the 1280 byte restriction.
Signed-off-by: Peter Oskolkov <posk@google.com>
Reported-by: Tom Herbert <tom@herbertland.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net/ipv6_frag.h')
-rw-r--r-- | include/net/ipv6_frag.h | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/include/net/ipv6_frag.h b/include/net/ipv6_frag.h index 6ced1e6899b6..28aa9b30aece 100644 --- a/include/net/ipv6_frag.h +++ b/include/net/ipv6_frag.h @@ -82,8 +82,15 @@ ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq) __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); /* Don't send error if the first segment did not arrive. */ - head = fq->q.fragments; - if (!(fq->q.flags & INET_FRAG_FIRST_IN) || !head) + if (!(fq->q.flags & INET_FRAG_FIRST_IN)) + goto out; + + /* sk_buff::dev and sk_buff::rbnode are unionized. So we + * pull the head out of the tree in order to be able to + * deal with head->dev. + */ + head = inet_frag_pull_head(&fq->q); + if (!head) goto out; head->dev = dev; |