Skip to content

Commit

Permalink
ipv6: no CHECKSUM_PARTIAL on MSG_MORE corked sockets
Browse files Browse the repository at this point in the history
We cannot reliable calculate packet size on MSG_MORE corked sockets
and thus cannot decide if they are going to be fragmented later on,
so better not use CHECKSUM_PARTIAL in the first place.

The IPv6 code also intended to protect and not use CHECKSUM_PARTIAL in
the existence of IPv6 extension headers, but the condition was wrong. Fix
it up, too. Also the condition to check whether the packet fits into
one fragment was wrong and has been corrected.

Fixes: commit 32dce96 ("ipv6: Allow for partial checksums on non-ufo packets")
See-also: commit 72e843b ("ipv6: ip6_fragment() should check CHECKSUM_PARTIAL")
Cc: Eric Dumazet <edumazet@google.com>
Cc: Vlad Yasevich <vyasevich@gmail.com>
Cc: Benjamin Coddington <bcodding@redhat.com>
Cc: Tom Herbert <tom@herbertland.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Hannes Frederic Sowa authored and David S. Miller committed Nov 1, 2015
1 parent dbd3393 commit 682b1a9
Showing 1 changed file with 33 additions and 37 deletions.
70 changes: 33 additions & 37 deletions net/ipv6/ip6_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,7 @@ static int __ip6_append_data(struct sock *sk,
struct rt6_info *rt = (struct rt6_info *)cork->dst;
struct ipv6_txoptions *opt = v6_cork->opt;
int csummode = CHECKSUM_NONE;
unsigned int maxnonfragsize, headersize;

skb = skb_peek_tail(queue);
if (!skb) {
Expand All @@ -1287,55 +1288,50 @@ static int __ip6_append_data(struct sock *sk,
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
sizeof(struct frag_hdr);

if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) {
unsigned int maxnonfragsize, headersize;

headersize = sizeof(struct ipv6hdr) +
(opt ? opt->opt_flen + opt->opt_nflen : 0) +
(dst_allfrag(&rt->dst) ?
sizeof(struct frag_hdr) : 0) +
rt->rt6i_nfheader_len;

if (ip6_sk_ignore_df(sk))
maxnonfragsize = sizeof(struct ipv6hdr) + IPV6_MAXPLEN;
else
maxnonfragsize = mtu;
headersize = sizeof(struct ipv6hdr) +
(opt ? opt->opt_flen + opt->opt_nflen : 0) +
(dst_allfrag(&rt->dst) ?
sizeof(struct frag_hdr) : 0) +
rt->rt6i_nfheader_len;

if (cork->length + length > mtu - headersize && dontfrag &&
(sk->sk_protocol == IPPROTO_UDP ||
sk->sk_protocol == IPPROTO_RAW)) {
ipv6_local_rxpmtu(sk, fl6, mtu - headersize +
sizeof(struct ipv6hdr));
goto emsgsize;
}

/* dontfrag active */
if ((cork->length + length > mtu - headersize) && dontfrag &&
(sk->sk_protocol == IPPROTO_UDP ||
sk->sk_protocol == IPPROTO_RAW)) {
ipv6_local_rxpmtu(sk, fl6, mtu - headersize +
sizeof(struct ipv6hdr));
goto emsgsize;
}
if (ip6_sk_ignore_df(sk))
maxnonfragsize = sizeof(struct ipv6hdr) + IPV6_MAXPLEN;
else
maxnonfragsize = mtu;

if (cork->length + length > maxnonfragsize - headersize) {
if (cork->length + length > maxnonfragsize - headersize) {
emsgsize:
ipv6_local_error(sk, EMSGSIZE, fl6,
mtu - headersize +
sizeof(struct ipv6hdr));
return -EMSGSIZE;
}
ipv6_local_error(sk, EMSGSIZE, fl6,
mtu - headersize +
sizeof(struct ipv6hdr));
return -EMSGSIZE;
}

/* CHECKSUM_PARTIAL only with no extension headers and when
* we are not going to fragment
*/
if (transhdrlen && sk->sk_protocol == IPPROTO_UDP &&
headersize == sizeof(struct ipv6hdr) &&
length < mtu - headersize &&
!(flags & MSG_MORE) &&
rt->dst.dev->features & NETIF_F_V6_CSUM)
csummode = CHECKSUM_PARTIAL;

if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) {
sock_tx_timestamp(sk, &tx_flags);
if (tx_flags & SKBTX_ANY_SW_TSTAMP &&
sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
tskey = sk->sk_tskey++;
}

/* If this is the first and only packet and device
* supports checksum offloading, let's use it.
* Use transhdrlen, same as IPv4, because partial
* sums only work when transhdrlen is set.
*/
if (transhdrlen && sk->sk_protocol == IPPROTO_UDP &&
length + fragheaderlen < mtu &&
rt->dst.dev->features & NETIF_F_V6_CSUM &&
!exthdrlen)
csummode = CHECKSUM_PARTIAL;
/*
* Let's try using as much space as possible.
* Use MTU if total length of the message fits into the MTU.
Expand Down

0 comments on commit 682b1a9

Please sign in to comment.