blob: 336620187cbbdd448047c4c1d0f3731b89c55fd1 [file] [log] [blame]
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
* This file has direct heritage from the SCTP user-level reference
* implementation by R. Stewart, et al. These functions implement the
* Adler-32 algorithm as specified by RFC 2960.
*
* The SCTP reference implementation 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 2, or (at your option)
* any later version.
*
* The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to the
* email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
*
* Written or modified by:
* Randall Stewart <rstewar1@email.mot.com>
* Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com>
* Sridhar Samudrala <sri@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
/* This is an entry point for external calls
* Define this function in the header file. This is
* direct from rfc1950, ...
*
* The following C code computes the Adler-32 checksum of a data buffer.
* It is written for clarity, not for speed. The sample code is in the
* ANSI C programming language. Non C users may find it easier to read
* with these hints:
*
* & Bitwise AND operator.
* >> Bitwise right shift operator. When applied to an
* unsigned quantity, as here, right shift inserts zero bit(s)
* at the left.
* << Bitwise left shift operator. Left shift inserts zero
* bit(s) at the right.
* ++ "n++" increments the variable n.
* % modulo operator: a % b is the remainder of a divided by b.
*
* Well, the above is a bit of a lie, I have optimized this a small
* tad, but I have commented the original lines below
*/
#include <linux/types.h>
#include <net/sctp/sctp.h>
#define BASE 65521 /* largest prime smaller than 65536 */
/* Performance work as shown this pig to be the
* worst CPU wise guy. I have done what I could think
* of on my flight to Austrialia but I am sure some
* clever assembly could speed this up, but of
* course this would require the dreaded #ifdef's for
* architecture. If you can speed this up more, pass
* it back and we will incorporate it :-)
*/
unsigned long update_adler32(unsigned long adler,
unsigned char *buf, int len)
{
__u32 s1 = adler & 0xffff;
__u32 s2 = (adler >> 16) & 0xffff;
int n;
for (n = 0; n < len; n++,buf++) {
/* s1 = (s1 + buf[n]) % BASE */
/* first we add */
s1 = (s1 + *buf);
/* Now if we need to, we do a mod by
* subtracting. It seems a bit faster
* since I really will only ever do
* one subtract at the MOST, since buf[n]
* is a max of 255.
*/
if (s1 >= BASE)
s1 -= BASE;
/* s2 = (s2 + s1) % BASE */
/* first we add */
s2 = (s2 + s1);
/* again, it is more efficent (it seems) to
* subtract since the most s2 will ever be
* is (BASE-1 + BASE-1) in the worse case.
* This would then be (2 * BASE) - 2, which
* will still only do one subtract. On Intel
* this is much better to do this way and
* avoid the divide. Have not -pg'd on
* sparc.
*/
if (s2 >= BASE) {
/* s2 %= BASE;*/
s2 -= BASE;
}
}
/* Return the adler32 of the bytes buf[0..len-1] */
return (s2 << 16) + s1;
}
__u32 sctp_start_cksum(__u8 *ptr, __u16 count)
{
/*
* Update a running Adler-32 checksum with the bytes
* buf[0..len-1] and return the updated checksum. The Adler-32
* checksum should be initialized to 1.
*/
__u32 adler = 1L;
__u32 zero = 0L;
/* Calculate the CRC up to the checksum field. */
adler = update_adler32(adler, ptr,
sizeof(struct sctphdr) - sizeof(__u32));
/* Skip over the checksum field. */
adler = update_adler32(adler, (unsigned char *) &zero,
sizeof(__u32));
ptr += sizeof(struct sctphdr);
count -= sizeof(struct sctphdr);
/* Calculate the rest of the Adler-32. */
adler = update_adler32(adler, ptr, count);
return adler;
}
__u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 adler)
{
adler = update_adler32(adler, ptr, count);
return adler;
}
__u32 sctp_end_cksum(__u32 adler)
{
return adler;
}