ipx_cksum.c revision 50477
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 * $FreeBSD: head/sys/netipx/ipx_cksum.c 50477 1999-08-28 01:08:13Z peter $ 37 */ 38 39#include <sys/param.h> 40#include <sys/mbuf.h> 41 42#include <netipx/ipx_var.h> 43 44/* 45 * Checksum routine for Network Systems Protocol Packets (Big-Endian). 46 * 47 * This routine is very heavily used in the network 48 * code and should be modified for each CPU to be as fast as possible. 49 */ 50 51#define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } 52#define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} 53 54u_short 55ipx_cksum(m, len) 56 struct mbuf *m; 57 int len; 58{ 59 register u_short *w; 60 register int sum = 0; 61 register int mlen = 0; 62 register int sum2; 63 64 union { 65 u_short s[2]; 66 long l; 67 } l_util; 68 69 for (;m != NULL && len; m = m->m_next) { 70 if (m->m_len == 0) 71 continue; 72 /* 73 * Each trip around loop adds in 74 * word from one mbuf segment. 75 */ 76 w = mtod(m, u_short *); 77 if (mlen == -1) { 78 /* 79 * There is a byte left from the last segment; 80 * ones-complement add it into the checksum. 81 */ 82#if BYTE_ORDER == BIG_ENDIAN 83 sum += *(u_char *)w; 84#else 85 sum += *(u_char *)w << 8; 86#endif 87 sum += sum; 88 w = (u_short *)(1 + (char *)w); 89 mlen = m->m_len - 1; 90 len--; 91 FOLD(sum); 92 } else 93 mlen = m->m_len; 94 if (len < mlen) 95 mlen = len; 96 len -= mlen; 97 /* 98 * We can do a 16 bit ones complement sum using 99 * 32 bit arithmetic registers for adding, 100 * with carries from the low added 101 * into the high (by normal carry-chaining) 102 * so long as we fold back before 16 carries have occured. 103 */ 104 if (1 & (int) w) 105 goto uuuuglyy; 106#ifndef TINY 107/* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ 108 while ((mlen -= 32) >= 0) { 109 sum += w[0]; sum += sum; sum += w[1]; sum += sum; 110 sum += w[2]; sum += sum; sum += w[3]; sum += sum; 111 sum += w[4]; sum += sum; sum += w[5]; sum += sum; 112 sum += w[6]; sum += sum; sum += w[7]; sum += sum; 113 FOLD(sum); 114 sum += w[8]; sum += sum; sum += w[9]; sum += sum; 115 sum += w[10]; sum += sum; sum += w[11]; sum += sum; 116 sum += w[12]; sum += sum; sum += w[13]; sum += sum; 117 sum += w[14]; sum += sum; sum += w[15]; sum += sum; 118 FOLD(sum); 119 w += 16; 120 } 121 mlen += 32; 122#endif 123 while ((mlen -= 8) >= 0) { 124 sum += w[0]; sum += sum; sum += w[1]; sum += sum; 125 sum += w[2]; sum += sum; sum += w[3]; sum += sum; 126 FOLD(sum); 127 w += 4; 128 } 129 mlen += 8; 130 while ((mlen -= 2) >= 0) { 131 sum += *w++; sum += sum; 132 } 133 goto commoncase; 134uuuuglyy: 135#if BYTE_ORDER == BIG_ENDIAN 136#define ww(n) (((u_char *)w)[n + n + 1]) 137#define vv(n) (((u_char *)w)[n + n]) 138#else 139#if BYTE_ORDER == LITTLE_ENDIAN 140#define vv(n) (((u_char *)w)[n + n + 1]) 141#define ww(n) (((u_char *)w)[n + n]) 142#endif 143#endif 144 sum2 = 0; 145#ifndef TINY 146 while ((mlen -= 32) >= 0) { 147 sum += ww(0); sum += sum; sum += ww(1); sum += sum; 148 sum += ww(2); sum += sum; sum += ww(3); sum += sum; 149 sum += ww(4); sum += sum; sum += ww(5); sum += sum; 150 sum += ww(6); sum += sum; sum += ww(7); sum += sum; 151 FOLD(sum); 152 sum += ww(8); sum += sum; sum += ww(9); sum += sum; 153 sum += ww(10); sum += sum; sum += ww(11); sum += sum; 154 sum += ww(12); sum += sum; sum += ww(13); sum += sum; 155 sum += ww(14); sum += sum; sum += ww(15); sum += sum; 156 FOLD(sum); 157 sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 158 sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 159 sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; 160 sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; 161 FOLD(sum2); 162 sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; 163 sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; 164 sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; 165 sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; 166 FOLD(sum2); 167 w += 16; 168 } 169 mlen += 32; 170#endif 171 while ((mlen -= 8) >= 0) { 172 sum += ww(0); sum += sum; sum += ww(1); sum += sum; 173 sum += ww(2); sum += sum; sum += ww(3); sum += sum; 174 FOLD(sum); 175 sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 176 sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 177 FOLD(sum2); 178 w += 4; 179 } 180 mlen += 8; 181 while ((mlen -= 2) >= 0) { 182 sum += ww(0); sum += sum; 183 sum2 += vv(0); sum2 += sum2; 184 w++; 185 } 186 sum += (sum2 << 8); 187commoncase: 188 if (mlen == -1) { 189#if BYTE_ORDER == BIG_ENDIAN 190 sum += *(u_char *)w << 8; 191#else 192 sum += *(u_char *)w; 193#endif 194 } 195 FOLD(sum); 196 } 197 if (mlen == -1) { 198 /* We had an odd number of bytes to sum; assume a garbage 199 byte of zero and clean up */ 200 sum += sum; 201 FOLD(sum); 202 } 203 /* 204 * sum has already been kept to low sixteen bits. 205 * just examine result and exit. 206 */ 207 if(sum == 0xffff) 208 sum = 0; 209 return (sum); 210} 211