1 /* 2 * Copyright (c) 1982, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ns_cksum.c 7.5 (Berkeley) 06/28/90 8 */ 9 10 #include "param.h" 11 #include "mbuf.h" 12 /* 13 * Checksum routine for Network Systems Protocol Packets (Big-Endian). 14 * 15 * This routine is very heavily used in the network 16 * code and should be modified for each CPU to be as fast as possible. 17 */ 18 19 #define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } 20 #define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} 21 22 u_short 23 ns_cksum(m, len) 24 register struct mbuf *m; 25 register int len; 26 { 27 register u_short *w; 28 register int sum = 0; 29 register int mlen = 0; 30 register int sum2; 31 32 union { 33 u_short s[2]; 34 long l; 35 } l_util; 36 37 for (;m && len; m = m->m_next) { 38 if (m->m_len == 0) 39 continue; 40 /* 41 * Each trip around loop adds in 42 * word from one mbuf segment. 43 */ 44 w = mtod(m, u_short *); 45 if (mlen == -1) { 46 /* 47 * There is a byte left from the last segment; 48 * ones-complement add it into the checksum. 49 */ 50 sum += *(u_char *)w; /* Big-Endian, else << 8 */ 51 sum += sum; 52 w = (u_short *)(1 + (char *)w); 53 mlen = m->m_len - 1; 54 len--; 55 FOLD(sum); 56 } else 57 mlen = m->m_len; 58 if (len < mlen) 59 mlen = len; 60 len -= mlen; 61 /* 62 * We can do a 16 bit ones complement sum using 63 * 32 bit arithmetic registers for adding, 64 * with carries from the low added 65 * into the high (by normal carry-chaining) 66 * so long as we fold back before 16 carries have occured. 67 */ 68 if (1 & (int) w) 69 goto uuuuglyy; 70 #ifndef TINY 71 /* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ 72 while ((mlen -= 32) >= 0) { 73 sum += w[0]; sum += sum; sum += w[1]; sum += sum; 74 sum += w[2]; sum += sum; sum += w[3]; sum += sum; 75 sum += w[4]; sum += sum; sum += w[5]; sum += sum; 76 sum += w[6]; sum += sum; sum += w[7]; sum += sum; 77 FOLD(sum); 78 sum += w[8]; sum += sum; sum += w[9]; sum += sum; 79 sum += w[10]; sum += sum; sum += w[11]; sum += sum; 80 sum += w[12]; sum += sum; sum += w[13]; sum += sum; 81 sum += w[14]; sum += sum; sum += w[15]; sum += sum; 82 FOLD(sum); 83 w += 16; 84 } 85 mlen += 32; 86 #endif 87 while ((mlen -= 8) >= 0) { 88 sum += w[0]; sum += sum; sum += w[1]; sum += sum; 89 sum += w[2]; sum += sum; sum += w[3]; sum += sum; 90 FOLD(sum); 91 w += 4; 92 } 93 mlen += 8; 94 while ((mlen -= 2) >= 0) { 95 sum += *w++; sum += sum; 96 } 97 goto commoncase; 98 uuuuglyy: 99 /* Big-Endian; else reverse ww and vv */ 100 #define ww(n) (((u_char *)w)[n + n + 1]) 101 #define vv(n) (((u_char *)w)[n + n]) 102 sum2 = 0; 103 #ifndef TINY 104 while ((mlen -= 32) >= 0) { 105 sum += ww(0); sum += sum; sum += ww(1); sum += sum; 106 sum += ww(2); sum += sum; sum += ww(3); sum += sum; 107 sum += ww(4); sum += sum; sum += ww(5); sum += sum; 108 sum += ww(6); sum += sum; sum += ww(7); sum += sum; 109 FOLD(sum); 110 sum += ww(8); sum += sum; sum += ww(9); sum += sum; 111 sum += ww(10); sum += sum; sum += ww(11); sum += sum; 112 sum += ww(12); sum += sum; sum += ww(13); sum += sum; 113 sum += ww(14); sum += sum; sum += ww(15); sum += sum; 114 FOLD(sum); 115 sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 116 sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 117 sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; 118 sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; 119 FOLD(sum2); 120 sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; 121 sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; 122 sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; 123 sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; 124 FOLD(sum2); 125 w += 16; 126 } 127 mlen += 32; 128 #endif 129 while ((mlen -= 8) >= 0) { 130 sum += ww(0); sum += sum; sum += ww(1); sum += sum; 131 sum += ww(2); sum += sum; sum += ww(3); sum += sum; 132 FOLD(sum); 133 sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; 134 sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; 135 FOLD(sum2); 136 w += 4; 137 } 138 mlen += 8; 139 while ((mlen -= 2) >= 0) { 140 sum += ww(0); sum += sum; 141 sum2 += vv(0); sum2 += sum2; 142 w++; 143 } 144 sum += (sum2 << 8); 145 commoncase: 146 if (mlen == -1) { 147 sum += *(u_char *)w << 8; /* Big-Endian, else no << 8 */ 148 } 149 FOLD(sum); 150 } 151 if (mlen == -1) { 152 /* We had an odd number of bytes to sum; assume a garbage 153 byte of zero and clean up */ 154 sum += sum; 155 FOLD(sum); 156 } 157 /* 158 * sum has already been kept to low sixteen bits. 159 * just examine result and exit. 160 */ 161 if(sum==0xffff) sum = 0; 162 return (sum); 163 } 164