netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* RFC2292(bis) checksum support
@ 2002-05-16 16:57 YOSHIFUJI Hideaki / 吉藤英明
  2002-05-19 21:46 ` kuznet
  0 siblings, 1 reply; 4+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2002-05-16 16:57 UTC (permalink / raw)
  To: netdev; +Cc: usagi

Hello!

According to RFC2292 and its successor RFC2292bis, kernel compute and 
store checksum for output, and verify the recieved checksum on input
(and discard it if it is in error) if the socket is for ICMPv6 IPV6_CHECKSUM
socket option is set to the raw socket.  
Linux does not support this.

Note: 

(1) RFC2292bis denies usage of this interface for ICMPv6 socket, but 
we allow it for a single case (offset is 2, which is correct value
for ICMPv6 checksum) for backward compatibility for older applications.

(2) RFC2292bis clarify that positive odd value is invalid, which cause
problems on interoperability.

<draft-ietf-ipngwg-rfc2292bis-07.txt>
3.1.  Checksums

   The kernel will calculate and insert the ICMPv6 checksum for ICMPv6
   raw sockets, since this checksum is mandatory.

   For other raw IPv6 sockets (that is, for raw IPv6 sockets created
   with a third argument other than IPPROTO_ICMPV6), the application
   must set the new IPV6_CHECKSUM socket option to have the kernel (1)
   compute and store a checksum for output, and (2) verify the received
   checksum on input, discarding the packet if the checksum is in error.
   This option prevents applications from having to perform source
   address selection on the packets they send.  The checksum will
   incorporate the IPv6 pseudo-header, defined in Section 8.1 of
   [RFC-2460].  This new socket option also specifies an integer offset
   into the user data of where the checksum is located.

       int  offset = 2;
       setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset));

   By default, this socket option is disabled.  Setting the offset to -1
   also disables the option.  By disabled we mean (1) the kernel will
   not calculate and store a checksum for outgoing packets, and (2) the
   kernel will not verify a checksum for received packets.

   This option assumes the use of the 16-bit one's complement of the
   one's complement sum as the checksum algorithm and that the checksum
   field is aligned on a 16-bit boundary.  Thus, specifying a positive
   odd value as offset is invalid, and setsockopt() will fail for such
   offset values.

   An attempt to set IPV6_CHECKSUM for an ICMPv6 socket will fail.
   Also, an attempt to set or get IPV6_CHECKSUM for a non-raw IPv6
   socket will fail.

   (Note: Since the checksum is always calculated by the kernel for an
   ICMPv6 socket, applications are not able to generate ICMPv6 packets
   with incorrect checksums (presumably for testing purposes) using this
   API.)
</draft-ietf-ipngwg-rfc2292bis-07.txt>

This patch is for linux-2.4.18.

Index: net/ipv6/raw.c
===================================================================
RCS file: /cvsroot/usagi/kernel/linux24/net/ipv6/raw.c,v
retrieving revision 1.1.1.10
retrieving revision 1.1.1.10.6.1
diff -u -r1.1.1.10 -r1.1.1.10.6.1
--- net/ipv6/raw.c	2001/09/24 07:07:15	1.1.1.10
+++ net/ipv6/raw.c	2002/05/16 00:25:21	1.1.1.10.6.1
@@ -11,6 +11,7 @@
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
+ * 	YOSHIFUJI,H.@USAGI	:	raw checksum (RFC2292(bis)) support
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -278,15 +279,34 @@
 
 static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
 {
-	/* Charge it to the socket. */
-	if (sock_queue_rcv_skb(sk,skb)<0) {
-		IP6_INC_STATS_BH(Ip6InDiscards);
-		kfree_skb(skb);
-		return 0;
+	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
+	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+
+	if (sk->tp_pinfo.tp_raw.checksum) {
+		if (skb->ip_summed == CHECKSUM_HW) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			if (csum_ipv6_magic(saddr, daddr, skb->len, sk->num,
+					    skb->csum))
+				skb->ip_summed = CHECKSUM_NONE;
+		}
+		if (skb->ip_summed == CHECKSUM_NONE) {
+			if (csum_ipv6_magic(saddr, daddr, skb->len, sk->num,
+					    skb_checksum(skb, 0, skb->len, 0)))
+				goto discard_it;
+		}
 	}
 
+	/* Charge it to the socket. */
+	if (sock_queue_rcv_skb(sk,skb)<0)
+		goto discard_it;
+
 	IP6_INC_STATS_BH(Ip6InDelivers);
 	return 0;
+
+discard_it:
+	IP6_INC_STATS_BH(Ip6InDiscards);
+	kfree_skb(skb);
+	return 0;
 }
 
 /*
@@ -415,11 +435,19 @@
 		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");
@@ -647,6 +675,12 @@
 
 	switch (optname) {
 		case IPV6_CHECKSUM:
+			if (sk->num == IPPROTO_ICMPV6 && val != 2)
+				return(-EINVAL);
+			/* 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 {
@@ -744,6 +778,11 @@
 
 static int rawv6_init_sk(struct sock *sk)
 {
+	if (sk->num == IPPROTO_ICMPV6){
+		struct raw6_opt *opt = &sk->tp_pinfo.tp_raw;
+		opt->checksum = 1;
+		opt->offset = 2;
+	}
 	return(0);
 }
 

-- 
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF  80D8 4807 F894 E062 0EEA

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: RFC2292(bis) checksum support
  2002-05-16 16:57 RFC2292(bis) checksum support YOSHIFUJI Hideaki / 吉藤英明
@ 2002-05-19 21:46 ` kuznet
  2002-05-20  3:04   ` YOSHIFUJI Hideaki / 吉藤英明
  0 siblings, 1 reply; 4+ messages in thread
From: kuznet @ 2002-05-19 21:46 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki; +Cc: netdev

Hello!

> According to RFC2292 and its successor RFC2292bis, kernel compute and 
> store checksum for output, and verify the recieved checksum on input
> (and discard it if it is in error) if the socket is for ICMPv6 IPV6_CHECKSUM
> socket option is set to the raw socket.  
> Linux does not support this.

This is supposed to be fixed in recent 2.4.19 and 2.5.


> (1) RFC2292bis denies usage of this interface for ICMPv6 socket,

OK. Yes, we can set default value for such sockets to 2, but I do not see
any good reasons to limit functionality of the API just to follow evident
mistake in the rfc. So, I would apply the last three chunks of the patch
except for these lines:

+                       if (sk->num == IPPROTO_ICMPV6 && val != 2)
+                               return(-EINVAL);


One question only: what did you mean in the following chunk?
Apparently, you forgot to delete marked line.

 			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;
+			}

Do I guess correctly that you wanted to compensate for occasionally
ununitialized checksum bits in data supplied by user?

Alexey

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: RFC2292(bis) checksum support
  2002-05-19 21:46 ` kuznet
@ 2002-05-20  3:04   ` YOSHIFUJI Hideaki / 吉藤英明
  2002-05-20  3:51     ` kuznet
  0 siblings, 1 reply; 4+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2002-05-20  3:04 UTC (permalink / raw)
  To: kuznet; +Cc: yoshfuji, netdev, usagi

In article <200205192146.BAA00826@sex.inr.ac.ru> (at Mon, 20 May 2002 01:46:48 +0400 (MSD)), kuznet@ms2.inr.ac.ru says:

> This is supposed to be fixed in recent 2.4.19 and 2.5.

thanks!!!


> > (1) RFC2292bis denies usage of this interface for ICMPv6 socket,
> 
> OK. Yes, we can set default value for such sockets to 2, but I do not see
> any good reasons to limit functionality of the API just to follow evident
> mistake in the rfc. So, I would apply the last three chunks of the patch
> except for these lines:
> 
> +                       if (sk->num == IPPROTO_ICMPV6 && val != 2)
> +                               return(-EINVAL);

Would you tell us what the "evident mistake in the rfc" is, please?

Checksum for ICMPv6 is mandatory like ones for TCP and UDP (for IPv6) are.
We should not (be able to) disable checksum for TCP, UDP AND ICMPv6,
should we?


> One question only: what did you mean in the following chunk?
> Apparently, you forgot to delete marked line.
> 
>  			csum = (__u16 *) (buff + opt->offset);
>  			*csum = hdr->cksum;
> 			^^^^^^^^^^^^^^^^^^^
:
> Do I guess correctly that you wanted to compensate for occasionally
> ununitialized checksum bits in data supplied by user?

yes.  I just forgot to delete that original line while making this patch;
sorry.

--yoshfuji

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: RFC2292(bis) checksum support
  2002-05-20  3:04   ` YOSHIFUJI Hideaki / 吉藤英明
@ 2002-05-20  3:51     ` kuznet
  0 siblings, 0 replies; 4+ messages in thread
From: kuznet @ 2002-05-20  3:51 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / 吉藤英明
  Cc: yoshfuji, netdev, usagi

Hello!

> Checksum for ICMPv6 is mandatory like ones for TCP and UDP (for IPv6) are.
> We should not (be able to) disable checksum for TCP, UDP AND ICMPv6,
> should we?

It is mandatory on _network level_, not on api level.
F.e. checksum is mandatory for ICMPv4 too, however, we used to calculate it
in user space and nobody cries about this.

Do you see what is the mistake in the rfc? Authors did a wrong sillogism
and had to write several paragraphs of meaningless text to explain the mess.

Shortly, you may consider this as a compatible extension of standard API.
(which costs deleting several lines of code. :-))


> yes.  I just forgot to delete that original line while making this patch;
> sorry.

OK.

Alexey

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2002-05-20  3:51 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-05-16 16:57 RFC2292(bis) checksum support YOSHIFUJI Hideaki / 吉藤英明
2002-05-19 21:46 ` kuznet
2002-05-20  3:04   ` YOSHIFUJI Hideaki / 吉藤英明
2002-05-20  3:51     ` kuznet

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).