ipx_cksum.c revision 25652
1/* 2 * Copyright (c) 1995, Mike Mitchell 3 * Copyright (c) 1982, 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)ipx_cksum.c 35 * 36 * $Id: ipx_cksum.c,v 1.5 1997/02/22 09:41:52 peter Exp $ 37 */ 38 39#include <sys/param.h> 40#include <sys/mbuf.h> 41#include <sys/socket.h> 42#include <sys/socketvar.h> 43 44#include <net/route.h> 45 46#include <netipx/ipx.h> 47#include <netipx/ipx_var.h> 48 49/* 50 * Checksum routine for Network Systems Protocol Packets (Big-Endian). 51 * 52 * This routine is very heavily used in the network 53 * code and should be modified for each CPU to be as fast as possible. 54 */ 55 56#define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } 57#define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} 58 59u_short 60ipx_cksum(m, len) 61 struct mbuf *m; 62 int len; 63{ 64 register u_short *w; 65 register int sum = 0; 66 register int mlen = 0; 67 register int sum2; 68 69 union { 70 u_short s[2]; 71 long l; 72 } l_util; 73 74 for (;m != NULL && len; m = m->m_next) { 75 if (m->m_len == 0) 76 continue; 77 /* 78 * Each trip around loop adds in 79 * word from one mbuf segment. 80 */ 81 w = mtod(m, u_short *); 82 if (mlen == -1) { 83 /* 84 * There is a byte left from the last segment; 85 * ones-complement add it into the checksum. 86 */ 87#if BYTE_ORDER == BIG_ENDIAN 88 sum += *(u_char *)w; 89#else 90 sum += *(u_char *)w << 8; 91#endif 92 sum += sum; 93 w = (u_short *)(1 + (char *)w); 94 mlen = m->m_len - 1; 95 len--; 96 FOLD(sum); 97 } else 98 mlen = m->m_len; 99 if (len < mlen) 100 mlen = len; 101 len -= mlen; 102 /* 103 * We can do a 16 bit ones complement sum using 104 * 32 bit arithmetic registers for adding, 105 * with carries from the low added 106 * into the high (by normal carry-chaining) 107 * so long as we fold back before 16 carries have occured. 108 */ 109 if (1 & (int) w) 110 goto uuuuglyy; 111#ifndef TINY 112/* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ 113 while ((mlen -= 32) >= 0) { 114 sum += w[0]; sum += sum; sum += w[1]; sum += sum; 115 sum += w[2]; sum += sum; sum += w[3]; sum += sum; 116 sum += w[4]; sum += sum; sum += w[5]; sum += sum; 117 sum += w[6]; sum += sum; sum += w[7]; sum += sum; 118 FOLD(sum); 119 sum += w[8]; sum += sum; sum += w[9]; sum += sum; 120 sum += w[10]; sum += sum; sum += w[11]; sum += sum; 121 sum += w[12]; sum += sum; sum += w[13]; sum += sum; 122 sum += w[14]; sum += sum; sum += w[15]; sum += sum; 123 FOLD(sum); 124 w += 16; 125 } 126 mlen += 32; 127#endif 128 while ((mlen -= 8) >= 0) { 129 sum += w[0]; sum += sum; sum += w[1]; sum += sum; 130 sum += w[2]; sum += sum; sum += w[3]; sum += sum; 131 FOLD(sum); 132 w += 4; 133 } 134 mlen += 8; 135 while ((mlen -= 2) >= 0) { 136 sum += *w++; sum += sum; 137 } 138 goto commoncase; 139uuuuglyy: 140#if BYTE_ORDER == BIG_ENDIAN 141#define ww(n) (((u_char *)w)[n + n + 1]) 142#define vv(n) (((u_char *)w)[n + n]) 143#else 144#if BYTE_ORDER == LITTLE_ENDIAN 145#define vv(n) (((u_char *)w)[n + n + 1]) 146#define ww(n) (((u_char *)w)[n + n]) 147#endif 148#endif 149 sum2 = 0; 150#ifndef TINY 151 while ((mlen -= 32) >= 0) { 152 sum += ww(0); sum += sum; sum += ww(1); sum += sum; 153 sum += ww(2); sum += sum; sum += ww(3); sum += sum; 154 sum += ww(4); sum += sum; sum += ww(5); sum += sum; 155 sum += ww(6); sum += sum; sum += ww(7); sum += sum; 156 FOLD(sum); 157 sum += ww(8); sum += sum; sum += ww(9); sum += sum; 158 sum += ww(10); sum += sum; sum += ww(11); sum += sum; 159 sum += ww(12); sum += sum; sum += ww(13); sum += sum; 160 sum += ww(14); sum += sum; sum += ww(15); sum += sum; 161 FOLD(sum); 162 sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 163 sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 164 sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; 165 sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; 166 FOLD(sum2); 167 sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; 168 sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; 169 sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; 170 sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; 171 FOLD(sum2); 172 w += 16; 173 } 174 mlen += 32; 175#endif 176 while ((mlen -= 8) >= 0) { 177 sum += ww(0); sum += sum; sum += ww(1); sum += sum; 178 sum += ww(2); sum += sum; sum += ww(3); sum += sum; 179 FOLD(sum); 180 sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 181 sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 182 FOLD(sum2); 183 w += 4; 184 } 185 mlen += 8; 186 while ((mlen -= 2) >= 0) { 187 sum += ww(0); sum += sum; 188 sum2 += vv(0); sum2 += sum2; 189 w++; 190 } 191 sum += (sum2 << 8); 192commoncase: 193 if (mlen == -1) { 194#if BYTE_ORDER == BIG_ENDIAN 195 sum += *(u_char *)w << 8; 196#else 197 sum += *(u_char *)w; 198#endif 199 } 200 FOLD(sum); 201 } 202 if (mlen == -1) { 203 /* We had an odd number of bytes to sum; assume a garbage 204 byte of zero and clean up */ 205 sum += sum; 206 FOLD(sum); 207 } 208 /* 209 * sum has already been kept to low sixteen bits. 210 * just examine result and exit. 211 */ 212 if(sum == 0xffff) 213 sum = 0; 214 return (sum); 215} 216