diff options
author | Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> | 2010-10-29 15:01:00 +0200 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2010-10-29 15:01:00 +0200 |
commit | 7193b28b672315fa79ffcbadc6f783f6a566286f (patch) | |
tree | 88af5f9b195ba6e9d43fd98f42caa2c7712733c0 /pfinet | |
parent | 0b6286a3c5eb86e3cca72d0840fc009855e4fba5 (diff) |
ipv6 raw fixes
- RFC2292 bis compliance: enable checksumming of ICMPv6 raw
sockets by default, reject odd offsets
- calculate checksum correctly when user forgets to
uninitialize checksum word
* net/ipv6/raw_ipv6.c (rawv6_frag_cksum): Fix offset check. Compensate for any
user-provided checksum.
(rawv6_setsockopt): Reject odd checkum offsets with EINVAL.
(rawv6_init_sk): Enable kernel-computed checksum by default for
IPPROTO_ICMPV6 sockets.
Diffstat (limited to 'pfinet')
-rw-r--r-- | pfinet/linux-src/net/ipv6/raw_ipv6.c | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/pfinet/linux-src/net/ipv6/raw_ipv6.c b/pfinet/linux-src/net/ipv6/raw_ipv6.c index 9980b3ad..6b93e0f2 100644 --- a/pfinet/linux-src/net/ipv6/raw_ipv6.c +++ b/pfinet/linux-src/net/ipv6/raw_ipv6.c @@ -9,6 +9,9 @@ * * $Id: raw_ipv6.c,v 1.2 2007/10/13 01:43:00 stesie Exp $ * + * Fixes: + * YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance) + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -334,11 +337,18 @@ static int rawv6_frag_cksum(const void *data, struct in6_addr *addr, hdr->cksum = csum_ipv6_magic(addr, daddr, hdr->len, hdr->proto, hdr->cksum); - if (opt->offset < len) { + if (opt->offset + 1 < len) { __u16 *csum; csum = (__u16 *) (buff + opt->offset); - *csum = hdr->cksum; + if (*csum) { + /* in case cksum was not initialized */ + __u32 sum = hdr->cksum; + sum += *csum; + *csum = hdr->cksum = (sum + (sum>>16)); + } else { + *csum = hdr->cksum; + } } else { if (net_ratelimit()) printk(KERN_DEBUG "icmp: cksum offset too big\n"); @@ -563,6 +573,10 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname, switch (optname) { case IPV6_CHECKSUM: + /* You may get strange result with a positive odd offset; + RFC2292bis agrees with me. */ + if (val > 0 && (val&1)) + return(-EINVAL); if (val < 0) { opt->checksum = 0; } else { @@ -638,6 +652,11 @@ static void rawv6_close(struct sock *sk, long timeout) static int rawv6_init_sk(struct sock *sk) { + if (sk->num == IPPROTO_ICMPV6){ + struct raw6_opt *opt = raw6_sk(sk); + opt->checksum = 1; + opt->offset = 2; + } return(0); } |