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 633597Ssklower * provided that this notice is preserved and that due credit is given 733597Ssklower * to the University of California at Berkeley. The name of the University 833597Ssklower * may not be used to endorse or promote products derived from this 933597Ssklower * software without specific prior written permission. This software 1033597Ssklower * is provided ``as is'' without express or implied warranty. 1133597Ssklower * 12*34496Skarels * @(#)ns_cksum.c 7.2 (Berkeley) 05/26/88 1325949Ssam */ 1425949Ssam #include "types.h" 1525949Ssam #include "mbuf.h" 1625949Ssam /* 1733634Ssklower * Checksum routine for Network Systems Protocol Packets (Big-Endian). 1825949Ssam * 1933597Ssklower * This routine is very heavily used in the network 2033597Ssklower * code and should be modified for each CPU to be as fast as possible. 2125949Ssam */ 2233597Ssklower 23*34496Skarels #define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } 24*34496Skarels #define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} 2533597Ssklower 2625949Ssam u_short 2725949Ssam ns_cksum(m, len) 2825949Ssam register struct mbuf *m; 2925949Ssam register int len; 3025949Ssam { 3133597Ssklower register u_short *w; 3233597Ssklower register int sum = 0; 3333597Ssklower register int mlen = 0; 3433597Ssklower register int sum2; 3525949Ssam 3633597Ssklower union { 3733597Ssklower u_short s[2]; 3833597Ssklower long l; 3933597Ssklower } l_util; 4033597Ssklower 4133597Ssklower for (;m && len; m = m->m_next) { 4233597Ssklower if (m->m_len == 0) 4333597Ssklower continue; 4433597Ssklower /* 4533597Ssklower * Each trip around loop adds in 4633597Ssklower * word from one mbuf segment. 4733597Ssklower */ 4833597Ssklower w = mtod(m, u_short *); 4933597Ssklower if (mlen == -1) { 5033597Ssklower /* 5133597Ssklower * There is a byte left from the last segment; 5233597Ssklower * ones-complement add it into the checksum. 5333597Ssklower */ 5433597Ssklower sum += *(u_char *)w; /* Big-Endian, else << 8 */ 5533597Ssklower sum += sum; 5633597Ssklower w = (u_short *)(1 + (char *)w); 5733597Ssklower mlen = m->m_len - 1; 5833597Ssklower len--; 5933597Ssklower FOLD(sum); 6033597Ssklower } else 6133597Ssklower mlen = m->m_len; 6233597Ssklower if (len < mlen) 6333597Ssklower mlen = len; 6433597Ssklower len -= mlen; 6533597Ssklower /* 6633597Ssklower * We can do a 16 bit ones complement sum using 6733597Ssklower * 32 bit arithmetic registers for adding, 6833597Ssklower * with carries from the low added 6933597Ssklower * into the high (by normal carry-chaining) 7033597Ssklower * so long as we fold back before 16 carries have occured. 7133597Ssklower */ 7233597Ssklower if (1 & (int) w) 7333597Ssklower goto uuuuglyy; 7433597Ssklower #ifndef TINY 7533597Ssklower /* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ 7633597Ssklower while ((mlen -= 32) >= 0) { 7733597Ssklower sum += w[0]; sum += sum; sum += w[1]; sum += sum; 7833597Ssklower sum += w[2]; sum += sum; sum += w[3]; sum += sum; 7933597Ssklower sum += w[4]; sum += sum; sum += w[5]; sum += sum; 8033597Ssklower sum += w[6]; sum += sum; sum += w[7]; sum += sum; 8133597Ssklower FOLD(sum); 8233597Ssklower sum += w[8]; sum += sum; sum += w[9]; sum += sum; 8333597Ssklower sum += w[10]; sum += sum; sum += w[11]; sum += sum; 8433597Ssklower sum += w[12]; sum += sum; sum += w[13]; sum += sum; 8533597Ssklower sum += w[14]; sum += sum; sum += w[15]; sum += sum; 8633597Ssklower FOLD(sum); 8733597Ssklower w += 16; 8825949Ssam } 8933597Ssklower mlen += 32; 9033597Ssklower #endif 9133597Ssklower while ((mlen -= 8) >= 0) { 9233597Ssklower sum += w[0]; sum += sum; sum += w[1]; sum += sum; 9333597Ssklower sum += w[2]; sum += sum; sum += w[3]; sum += sum; 9433597Ssklower FOLD(sum); 9533597Ssklower w += 4; 9633597Ssklower } 9733597Ssklower mlen += 8; 9833597Ssklower while ((mlen -= 2) >= 0) { 9933597Ssklower sum += *w++; sum += sum; 10033597Ssklower } 10133597Ssklower goto commoncase; 10233597Ssklower uuuuglyy: 10333597Ssklower /* Big-Endian; else reverse ww and vv */ 10433634Ssklower #define ww(n) (((u_char *)w)[n + n + 1]) 10533634Ssklower #define vv(n) (((u_char *)w)[n + n]) 10633597Ssklower sum2 = 0; 10733597Ssklower #ifndef TINY 10833597Ssklower while ((mlen -= 32) >= 0) { 10933597Ssklower sum += ww(0); sum += sum; sum += ww(1); sum += sum; 11033597Ssklower sum += ww(2); sum += sum; sum += ww(3); sum += sum; 11133597Ssklower sum += ww(4); sum += sum; sum += ww(5); sum += sum; 11233597Ssklower sum += ww(6); sum += sum; sum += ww(7); sum += sum; 11333597Ssklower FOLD(sum); 11433597Ssklower sum += ww(8); sum += sum; sum += ww(9); sum += sum; 11533597Ssklower sum += ww(10); sum += sum; sum += ww(11); sum += sum; 11633597Ssklower sum += ww(12); sum += sum; sum += ww(13); sum += sum; 11733597Ssklower sum += ww(14); sum += sum; sum += ww(15); sum += sum; 11833597Ssklower FOLD(sum); 11933597Ssklower sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 12033597Ssklower sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 12133597Ssklower sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; 12233597Ssklower sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; 12333597Ssklower FOLD(sum2); 12433597Ssklower sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; 12533597Ssklower sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; 12633597Ssklower sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; 12733597Ssklower sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; 12833597Ssklower FOLD(sum2); 12933597Ssklower w += 16; 13033597Ssklower } 13133597Ssklower mlen += 32; 13233597Ssklower #endif 13333597Ssklower while ((mlen -= 8) >= 0) { 13433597Ssklower sum += ww(0); sum += sum; sum += ww(1); sum += sum; 13533597Ssklower sum += ww(2); sum += sum; sum += ww(3); sum += sum; 13633597Ssklower FOLD(sum); 13733597Ssklower sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 13833597Ssklower sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 13933597Ssklower FOLD(sum2); 14033597Ssklower w += 4; 14133597Ssklower } 14233597Ssklower mlen += 8; 14333597Ssklower while ((mlen -= 2) >= 0) { 14433597Ssklower sum += ww(0); sum += sum; 14533597Ssklower sum2 += vv(0); sum2 += sum2; 14633597Ssklower w++; 14733597Ssklower } 14833597Ssklower sum += (sum2 << 8); 14933597Ssklower commoncase: 15033597Ssklower if (mlen == -1) { 15133597Ssklower sum += *(u_char *)w << 8; /* Big-Endian, else no << 8 */ 15233597Ssklower } 15333597Ssklower FOLD(sum); 15425949Ssam } 15533597Ssklower if (mlen == -1) { 15633597Ssklower /* We had an odd number of bytes to sum; assume a garbage 15733597Ssklower byte of zero and clean up */ 15833597Ssklower sum += sum; 15933597Ssklower FOLD(sum); 16033597Ssklower } 16133597Ssklower /* 16233597Ssklower * sum has already been kept to low sixteen bits. 16333597Ssklower * just examine result and exit. 16433597Ssklower */ 16533597Ssklower if(sum==0xffff) sum = 0; 16633597Ssklower return (sum); 16725949Ssam } 168