125949Ssam /* 233597Ssklower * Copyright (c) 1982, 1988 Regents of the University of California. 333597Ssklower * All rights reserved. 433597Ssklower * 5*44529Sbostic * %sccs.include.redist.c% 633597Ssklower * 7*44529Sbostic * @(#)ns_cksum.c 7.5 (Berkeley) 06/28/90 825949Ssam */ 934863Sbostic 1038987Ssklower #include "param.h" 1125949Ssam #include "mbuf.h" 1225949Ssam /* 1333634Ssklower * Checksum routine for Network Systems Protocol Packets (Big-Endian). 1425949Ssam * 1533597Ssklower * This routine is very heavily used in the network 1633597Ssklower * code and should be modified for each CPU to be as fast as possible. 1725949Ssam */ 1833597Ssklower 1934496Skarels #define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } 2034496Skarels #define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} 2133597Ssklower 2225949Ssam u_short 2325949Ssam ns_cksum(m, len) 2425949Ssam register struct mbuf *m; 2525949Ssam register int len; 2625949Ssam { 2733597Ssklower register u_short *w; 2833597Ssklower register int sum = 0; 2933597Ssklower register int mlen = 0; 3033597Ssklower register int sum2; 3125949Ssam 3233597Ssklower union { 3333597Ssklower u_short s[2]; 3433597Ssklower long l; 3533597Ssklower } l_util; 3633597Ssklower 3733597Ssklower for (;m && len; m = m->m_next) { 3833597Ssklower if (m->m_len == 0) 3933597Ssklower continue; 4033597Ssklower /* 4133597Ssklower * Each trip around loop adds in 4233597Ssklower * word from one mbuf segment. 4333597Ssklower */ 4433597Ssklower w = mtod(m, u_short *); 4533597Ssklower if (mlen == -1) { 4633597Ssklower /* 4733597Ssklower * There is a byte left from the last segment; 4833597Ssklower * ones-complement add it into the checksum. 4933597Ssklower */ 5033597Ssklower sum += *(u_char *)w; /* Big-Endian, else << 8 */ 5133597Ssklower sum += sum; 5233597Ssklower w = (u_short *)(1 + (char *)w); 5333597Ssklower mlen = m->m_len - 1; 5433597Ssklower len--; 5533597Ssklower FOLD(sum); 5633597Ssklower } else 5733597Ssklower mlen = m->m_len; 5833597Ssklower if (len < mlen) 5933597Ssklower mlen = len; 6033597Ssklower len -= mlen; 6133597Ssklower /* 6233597Ssklower * We can do a 16 bit ones complement sum using 6333597Ssklower * 32 bit arithmetic registers for adding, 6433597Ssklower * with carries from the low added 6533597Ssklower * into the high (by normal carry-chaining) 6633597Ssklower * so long as we fold back before 16 carries have occured. 6733597Ssklower */ 6833597Ssklower if (1 & (int) w) 6933597Ssklower goto uuuuglyy; 7033597Ssklower #ifndef TINY 7133597Ssklower /* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ 7233597Ssklower while ((mlen -= 32) >= 0) { 7333597Ssklower sum += w[0]; sum += sum; sum += w[1]; sum += sum; 7433597Ssklower sum += w[2]; sum += sum; sum += w[3]; sum += sum; 7533597Ssklower sum += w[4]; sum += sum; sum += w[5]; sum += sum; 7633597Ssklower sum += w[6]; sum += sum; sum += w[7]; sum += sum; 7733597Ssklower FOLD(sum); 7833597Ssklower sum += w[8]; sum += sum; sum += w[9]; sum += sum; 7933597Ssklower sum += w[10]; sum += sum; sum += w[11]; sum += sum; 8033597Ssklower sum += w[12]; sum += sum; sum += w[13]; sum += sum; 8133597Ssklower sum += w[14]; sum += sum; sum += w[15]; sum += sum; 8233597Ssklower FOLD(sum); 8333597Ssklower w += 16; 8425949Ssam } 8533597Ssklower mlen += 32; 8633597Ssklower #endif 8733597Ssklower while ((mlen -= 8) >= 0) { 8833597Ssklower sum += w[0]; sum += sum; sum += w[1]; sum += sum; 8933597Ssklower sum += w[2]; sum += sum; sum += w[3]; sum += sum; 9033597Ssklower FOLD(sum); 9133597Ssklower w += 4; 9233597Ssklower } 9333597Ssklower mlen += 8; 9433597Ssklower while ((mlen -= 2) >= 0) { 9533597Ssklower sum += *w++; sum += sum; 9633597Ssklower } 9733597Ssklower goto commoncase; 9833597Ssklower uuuuglyy: 9933597Ssklower /* Big-Endian; else reverse ww and vv */ 10033634Ssklower #define ww(n) (((u_char *)w)[n + n + 1]) 10133634Ssklower #define vv(n) (((u_char *)w)[n + n]) 10233597Ssklower sum2 = 0; 10333597Ssklower #ifndef TINY 10433597Ssklower while ((mlen -= 32) >= 0) { 10533597Ssklower sum += ww(0); sum += sum; sum += ww(1); sum += sum; 10633597Ssklower sum += ww(2); sum += sum; sum += ww(3); sum += sum; 10733597Ssklower sum += ww(4); sum += sum; sum += ww(5); sum += sum; 10833597Ssklower sum += ww(6); sum += sum; sum += ww(7); sum += sum; 10933597Ssklower FOLD(sum); 11033597Ssklower sum += ww(8); sum += sum; sum += ww(9); sum += sum; 11133597Ssklower sum += ww(10); sum += sum; sum += ww(11); sum += sum; 11233597Ssklower sum += ww(12); sum += sum; sum += ww(13); sum += sum; 11333597Ssklower sum += ww(14); sum += sum; sum += ww(15); sum += sum; 11433597Ssklower FOLD(sum); 11533597Ssklower sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 11633597Ssklower sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 11733597Ssklower sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; 11833597Ssklower sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; 11933597Ssklower FOLD(sum2); 12033597Ssklower sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; 12133597Ssklower sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; 12233597Ssklower sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; 12333597Ssklower sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; 12433597Ssklower FOLD(sum2); 12533597Ssklower w += 16; 12633597Ssklower } 12733597Ssklower mlen += 32; 12833597Ssklower #endif 12933597Ssklower while ((mlen -= 8) >= 0) { 13033597Ssklower sum += ww(0); sum += sum; sum += ww(1); sum += sum; 13133597Ssklower sum += ww(2); sum += sum; sum += ww(3); sum += sum; 13233597Ssklower FOLD(sum); 13333597Ssklower sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 13433597Ssklower sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 13533597Ssklower FOLD(sum2); 13633597Ssklower w += 4; 13733597Ssklower } 13833597Ssklower mlen += 8; 13933597Ssklower while ((mlen -= 2) >= 0) { 14033597Ssklower sum += ww(0); sum += sum; 14133597Ssklower sum2 += vv(0); sum2 += sum2; 14233597Ssklower w++; 14333597Ssklower } 14433597Ssklower sum += (sum2 << 8); 14533597Ssklower commoncase: 14633597Ssklower if (mlen == -1) { 14733597Ssklower sum += *(u_char *)w << 8; /* Big-Endian, else no << 8 */ 14833597Ssklower } 14933597Ssklower FOLD(sum); 15025949Ssam } 15133597Ssklower if (mlen == -1) { 15233597Ssklower /* We had an odd number of bytes to sum; assume a garbage 15333597Ssklower byte of zero and clean up */ 15433597Ssklower sum += sum; 15533597Ssklower FOLD(sum); 15633597Ssklower } 15733597Ssklower /* 15833597Ssklower * sum has already been kept to low sixteen bits. 15933597Ssklower * just examine result and exit. 16033597Ssklower */ 16133597Ssklower if(sum==0xffff) sum = 0; 16233597Ssklower return (sum); 16325949Ssam } 164