summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Kuznetsov <kuznet@ms2.inr.ac.ru>2010-10-29 15:01:00 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2010-10-29 15:01:00 +0200
commit7193b28b672315fa79ffcbadc6f783f6a566286f (patch)
tree88af5f9b195ba6e9d43fd98f42caa2c7712733c0
parent0b6286a3c5eb86e3cca72d0840fc009855e4fba5 (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.
-rw-r--r--pfinet/linux-src/net/ipv6/raw_ipv6.c23
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);
}