From 7193b28b672315fa79ffcbadc6f783f6a566286f Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Fri, 29 Oct 2010 15:01:00 +0200 Subject: 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. --- pfinet/linux-src/net/ipv6/raw_ipv6.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'pfinet') 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); } -- cgit v1.2.3