125949Ssam /* 2*63231Sbostic * Copyright (c) 1982, 1992, 1993 3*63231Sbostic * The Regents of the University of California. All rights reserved. 433597Ssklower * 544529Sbostic * %sccs.include.redist.c% 633597Ssklower * 7*63231Sbostic * @(#)ns_cksum.c 8.1 (Berkeley) 06/10/93 825949Ssam */ 934863Sbostic 1056534Sbostic #include <sys/param.h> 1156534Sbostic #include <sys/mbuf.h> 1245798Sbostic 1325949Ssam /* 1433634Ssklower * Checksum routine for Network Systems Protocol Packets (Big-Endian). 1525949Ssam * 1633597Ssklower * This routine is very heavily used in the network 1733597Ssklower * code and should be modified for each CPU to be as fast as possible. 1825949Ssam */ 1933597Ssklower 2034496Skarels #define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } 2134496Skarels #define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} 2233597Ssklower 2325949Ssam u_short ns_cksum(m,len)2425949Ssamns_cksum(m, len) 2525949Ssam register struct mbuf *m; 2625949Ssam register int len; 2725949Ssam { 2833597Ssklower register u_short *w; 2933597Ssklower register int sum = 0; 3033597Ssklower register int mlen = 0; 3133597Ssklower register int sum2; 3225949Ssam 3333597Ssklower union { 3433597Ssklower u_short s[2]; 3533597Ssklower long l; 3633597Ssklower } l_util; 3733597Ssklower 3833597Ssklower for (;m && len; m = m->m_next) { 3933597Ssklower if (m->m_len == 0) 4033597Ssklower continue; 4133597Ssklower /* 4233597Ssklower * Each trip around loop adds in 4333597Ssklower * word from one mbuf segment. 4433597Ssklower */ 4533597Ssklower w = mtod(m, u_short *); 4633597Ssklower if (mlen == -1) { 4733597Ssklower /* 4833597Ssklower * There is a byte left from the last segment; 4933597Ssklower * ones-complement add it into the checksum. 5033597Ssklower */ 5148841Ssklower #if BYTE_ORDER == BIG_ENDIAN 5248841Ssklower sum += *(u_char *)w; 5348841Ssklower #else 5448841Ssklower sum += *(u_char *)w << 8; 5548841Ssklower #endif 5633597Ssklower sum += sum; 5733597Ssklower w = (u_short *)(1 + (char *)w); 5833597Ssklower mlen = m->m_len - 1; 5933597Ssklower len--; 6033597Ssklower FOLD(sum); 6133597Ssklower } else 6233597Ssklower mlen = m->m_len; 6333597Ssklower if (len < mlen) 6433597Ssklower mlen = len; 6533597Ssklower len -= mlen; 6633597Ssklower /* 6733597Ssklower * We can do a 16 bit ones complement sum using 6833597Ssklower * 32 bit arithmetic registers for adding, 6933597Ssklower * with carries from the low added 7033597Ssklower * into the high (by normal carry-chaining) 7133597Ssklower * so long as we fold back before 16 carries have occured. 7233597Ssklower */ 7333597Ssklower if (1 & (int) w) 7433597Ssklower goto uuuuglyy; 7533597Ssklower #ifndef TINY 7633597Ssklower /* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ 7733597Ssklower while ((mlen -= 32) >= 0) { 7833597Ssklower sum += w[0]; sum += sum; sum += w[1]; sum += sum; 7933597Ssklower sum += w[2]; sum += sum; sum += w[3]; sum += sum; 8033597Ssklower sum += w[4]; sum += sum; sum += w[5]; sum += sum; 8133597Ssklower sum += w[6]; sum += sum; sum += w[7]; sum += sum; 8233597Ssklower FOLD(sum); 8333597Ssklower sum += w[8]; sum += sum; sum += w[9]; sum += sum; 8433597Ssklower sum += w[10]; sum += sum; sum += w[11]; sum += sum; 8533597Ssklower sum += w[12]; sum += sum; sum += w[13]; sum += sum; 8633597Ssklower sum += w[14]; sum += sum; sum += w[15]; sum += sum; 8733597Ssklower FOLD(sum); 8833597Ssklower w += 16; 8925949Ssam } 9033597Ssklower mlen += 32; 9133597Ssklower #endif 9233597Ssklower while ((mlen -= 8) >= 0) { 9333597Ssklower sum += w[0]; sum += sum; sum += w[1]; sum += sum; 9433597Ssklower sum += w[2]; sum += sum; sum += w[3]; sum += sum; 9533597Ssklower FOLD(sum); 9633597Ssklower w += 4; 9733597Ssklower } 9833597Ssklower mlen += 8; 9933597Ssklower while ((mlen -= 2) >= 0) { 10033597Ssklower sum += *w++; sum += sum; 10133597Ssklower } 10233597Ssklower goto commoncase; 10333597Ssklower uuuuglyy: 10448841Ssklower #if BYTE_ORDER == BIG_ENDIAN 10533634Ssklower #define ww(n) (((u_char *)w)[n + n + 1]) 10633634Ssklower #define vv(n) (((u_char *)w)[n + n]) 10748841Ssklower #else 10848841Ssklower #if BYTE_ORDER == LITTLE_ENDIAN 10948841Ssklower #define vv(n) (((u_char *)w)[n + n + 1]) 11048841Ssklower #define ww(n) (((u_char *)w)[n + n]) 11148841Ssklower #endif 11248841Ssklower #endif 11333597Ssklower sum2 = 0; 11433597Ssklower #ifndef TINY 11533597Ssklower while ((mlen -= 32) >= 0) { 11633597Ssklower sum += ww(0); sum += sum; sum += ww(1); sum += sum; 11733597Ssklower sum += ww(2); sum += sum; sum += ww(3); sum += sum; 11833597Ssklower sum += ww(4); sum += sum; sum += ww(5); sum += sum; 11933597Ssklower sum += ww(6); sum += sum; sum += ww(7); sum += sum; 12033597Ssklower FOLD(sum); 12133597Ssklower sum += ww(8); sum += sum; sum += ww(9); sum += sum; 12233597Ssklower sum += ww(10); sum += sum; sum += ww(11); sum += sum; 12333597Ssklower sum += ww(12); sum += sum; sum += ww(13); sum += sum; 12433597Ssklower sum += ww(14); sum += sum; sum += ww(15); sum += sum; 12533597Ssklower FOLD(sum); 12633597Ssklower sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 12733597Ssklower sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 12833597Ssklower sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; 12933597Ssklower sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; 13033597Ssklower FOLD(sum2); 13133597Ssklower sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; 13233597Ssklower sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; 13333597Ssklower sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; 13433597Ssklower sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; 13533597Ssklower FOLD(sum2); 13633597Ssklower w += 16; 13733597Ssklower } 13833597Ssklower mlen += 32; 13933597Ssklower #endif 14033597Ssklower while ((mlen -= 8) >= 0) { 14133597Ssklower sum += ww(0); sum += sum; sum += ww(1); sum += sum; 14233597Ssklower sum += ww(2); sum += sum; sum += ww(3); sum += sum; 14333597Ssklower FOLD(sum); 14433597Ssklower sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 14533597Ssklower sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 14633597Ssklower FOLD(sum2); 14733597Ssklower w += 4; 14833597Ssklower } 14933597Ssklower mlen += 8; 15033597Ssklower while ((mlen -= 2) >= 0) { 15133597Ssklower sum += ww(0); sum += sum; 15233597Ssklower sum2 += vv(0); sum2 += sum2; 15333597Ssklower w++; 15433597Ssklower } 15533597Ssklower sum += (sum2 << 8); 15633597Ssklower commoncase: 15733597Ssklower if (mlen == -1) { 15848841Ssklower #if BYTE_ORDER == BIG_ENDIAN 15948841Ssklower sum += *(u_char *)w << 8; 16048841Ssklower #else 16148841Ssklower sum += *(u_char *)w; 16248841Ssklower #endif 16333597Ssklower } 16433597Ssklower FOLD(sum); 16525949Ssam } 16633597Ssklower if (mlen == -1) { 16733597Ssklower /* We had an odd number of bytes to sum; assume a garbage 16833597Ssklower byte of zero and clean up */ 16933597Ssklower sum += sum; 17033597Ssklower FOLD(sum); 17133597Ssklower } 17233597Ssklower /* 17333597Ssklower * sum has already been kept to low sixteen bits. 17433597Ssklower * just examine result and exit. 17533597Ssklower */ 17633597Ssklower if(sum==0xffff) sum = 0; 17733597Ssklower return (sum); 17825949Ssam } 179