125949Ssam /* 233597Ssklower * Copyright (c) 1982, 1988 Regents of the University of California. 333597Ssklower * All rights reserved. 433597Ssklower * 533597Ssklower * Redistribution and use in source and binary forms are permitted 6*34863Sbostic * provided that the above copyright notice and this paragraph are 7*34863Sbostic * duplicated in all such forms and that any documentation, 8*34863Sbostic * advertising materials, and other materials related to such 9*34863Sbostic * distribution and use acknowledge that the software was developed 10*34863Sbostic * by the University of California, Berkeley. The name of the 11*34863Sbostic * University may not be used to endorse or promote products derived 12*34863Sbostic * from this software without specific prior written permission. 13*34863Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34863Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34863Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633597Ssklower * 17*34863Sbostic * @(#)ns_cksum.c 7.3 (Berkeley) 06/29/88 1825949Ssam */ 19*34863Sbostic 2025949Ssam #include "types.h" 2125949Ssam #include "mbuf.h" 2225949Ssam /* 2333634Ssklower * Checksum routine for Network Systems Protocol Packets (Big-Endian). 2425949Ssam * 2533597Ssklower * This routine is very heavily used in the network 2633597Ssklower * code and should be modified for each CPU to be as fast as possible. 2725949Ssam */ 2833597Ssklower 2934496Skarels #define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } 3034496Skarels #define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} 3133597Ssklower 3225949Ssam u_short 3325949Ssam ns_cksum(m, len) 3425949Ssam register struct mbuf *m; 3525949Ssam register int len; 3625949Ssam { 3733597Ssklower register u_short *w; 3833597Ssklower register int sum = 0; 3933597Ssklower register int mlen = 0; 4033597Ssklower register int sum2; 4125949Ssam 4233597Ssklower union { 4333597Ssklower u_short s[2]; 4433597Ssklower long l; 4533597Ssklower } l_util; 4633597Ssklower 4733597Ssklower for (;m && len; m = m->m_next) { 4833597Ssklower if (m->m_len == 0) 4933597Ssklower continue; 5033597Ssklower /* 5133597Ssklower * Each trip around loop adds in 5233597Ssklower * word from one mbuf segment. 5333597Ssklower */ 5433597Ssklower w = mtod(m, u_short *); 5533597Ssklower if (mlen == -1) { 5633597Ssklower /* 5733597Ssklower * There is a byte left from the last segment; 5833597Ssklower * ones-complement add it into the checksum. 5933597Ssklower */ 6033597Ssklower sum += *(u_char *)w; /* Big-Endian, else << 8 */ 6133597Ssklower sum += sum; 6233597Ssklower w = (u_short *)(1 + (char *)w); 6333597Ssklower mlen = m->m_len - 1; 6433597Ssklower len--; 6533597Ssklower FOLD(sum); 6633597Ssklower } else 6733597Ssklower mlen = m->m_len; 6833597Ssklower if (len < mlen) 6933597Ssklower mlen = len; 7033597Ssklower len -= mlen; 7133597Ssklower /* 7233597Ssklower * We can do a 16 bit ones complement sum using 7333597Ssklower * 32 bit arithmetic registers for adding, 7433597Ssklower * with carries from the low added 7533597Ssklower * into the high (by normal carry-chaining) 7633597Ssklower * so long as we fold back before 16 carries have occured. 7733597Ssklower */ 7833597Ssklower if (1 & (int) w) 7933597Ssklower goto uuuuglyy; 8033597Ssklower #ifndef TINY 8133597Ssklower /* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ 8233597Ssklower while ((mlen -= 32) >= 0) { 8333597Ssklower sum += w[0]; sum += sum; sum += w[1]; sum += sum; 8433597Ssklower sum += w[2]; sum += sum; sum += w[3]; sum += sum; 8533597Ssklower sum += w[4]; sum += sum; sum += w[5]; sum += sum; 8633597Ssklower sum += w[6]; sum += sum; sum += w[7]; sum += sum; 8733597Ssklower FOLD(sum); 8833597Ssklower sum += w[8]; sum += sum; sum += w[9]; sum += sum; 8933597Ssklower sum += w[10]; sum += sum; sum += w[11]; sum += sum; 9033597Ssklower sum += w[12]; sum += sum; sum += w[13]; sum += sum; 9133597Ssklower sum += w[14]; sum += sum; sum += w[15]; sum += sum; 9233597Ssklower FOLD(sum); 9333597Ssklower w += 16; 9425949Ssam } 9533597Ssklower mlen += 32; 9633597Ssklower #endif 9733597Ssklower while ((mlen -= 8) >= 0) { 9833597Ssklower sum += w[0]; sum += sum; sum += w[1]; sum += sum; 9933597Ssklower sum += w[2]; sum += sum; sum += w[3]; sum += sum; 10033597Ssklower FOLD(sum); 10133597Ssklower w += 4; 10233597Ssklower } 10333597Ssklower mlen += 8; 10433597Ssklower while ((mlen -= 2) >= 0) { 10533597Ssklower sum += *w++; sum += sum; 10633597Ssklower } 10733597Ssklower goto commoncase; 10833597Ssklower uuuuglyy: 10933597Ssklower /* Big-Endian; else reverse ww and vv */ 11033634Ssklower #define ww(n) (((u_char *)w)[n + n + 1]) 11133634Ssklower #define vv(n) (((u_char *)w)[n + n]) 11233597Ssklower sum2 = 0; 11333597Ssklower #ifndef TINY 11433597Ssklower while ((mlen -= 32) >= 0) { 11533597Ssklower sum += ww(0); sum += sum; sum += ww(1); sum += sum; 11633597Ssklower sum += ww(2); sum += sum; sum += ww(3); sum += sum; 11733597Ssklower sum += ww(4); sum += sum; sum += ww(5); sum += sum; 11833597Ssklower sum += ww(6); sum += sum; sum += ww(7); sum += sum; 11933597Ssklower FOLD(sum); 12033597Ssklower sum += ww(8); sum += sum; sum += ww(9); sum += sum; 12133597Ssklower sum += ww(10); sum += sum; sum += ww(11); sum += sum; 12233597Ssklower sum += ww(12); sum += sum; sum += ww(13); sum += sum; 12333597Ssklower sum += ww(14); sum += sum; sum += ww(15); sum += sum; 12433597Ssklower FOLD(sum); 12533597Ssklower sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 12633597Ssklower sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 12733597Ssklower sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; 12833597Ssklower sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; 12933597Ssklower FOLD(sum2); 13033597Ssklower sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; 13133597Ssklower sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; 13233597Ssklower sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; 13333597Ssklower sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; 13433597Ssklower FOLD(sum2); 13533597Ssklower w += 16; 13633597Ssklower } 13733597Ssklower mlen += 32; 13833597Ssklower #endif 13933597Ssklower while ((mlen -= 8) >= 0) { 14033597Ssklower sum += ww(0); sum += sum; sum += ww(1); sum += sum; 14133597Ssklower sum += ww(2); sum += sum; sum += ww(3); sum += sum; 14233597Ssklower FOLD(sum); 14333597Ssklower sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 14433597Ssklower sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 14533597Ssklower FOLD(sum2); 14633597Ssklower w += 4; 14733597Ssklower } 14833597Ssklower mlen += 8; 14933597Ssklower while ((mlen -= 2) >= 0) { 15033597Ssklower sum += ww(0); sum += sum; 15133597Ssklower sum2 += vv(0); sum2 += sum2; 15233597Ssklower w++; 15333597Ssklower } 15433597Ssklower sum += (sum2 << 8); 15533597Ssklower commoncase: 15633597Ssklower if (mlen == -1) { 15733597Ssklower sum += *(u_char *)w << 8; /* Big-Endian, else no << 8 */ 15833597Ssklower } 15933597Ssklower FOLD(sum); 16025949Ssam } 16133597Ssklower if (mlen == -1) { 16233597Ssklower /* We had an odd number of bytes to sum; assume a garbage 16333597Ssklower byte of zero and clean up */ 16433597Ssklower sum += sum; 16533597Ssklower FOLD(sum); 16633597Ssklower } 16733597Ssklower /* 16833597Ssklower * sum has already been kept to low sixteen bits. 16933597Ssklower * just examine result and exit. 17033597Ssklower */ 17133597Ssklower if(sum==0xffff) sum = 0; 17233597Ssklower return (sum); 17325949Ssam } 174