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