|
Lines 38-210
Link Here
|
| 38 |
|
38 |
|
| 39 |
#include <sys/param.h> |
39 |
#include <sys/param.h> |
| 40 |
#include <sys/mbuf.h> |
40 |
#include <sys/mbuf.h> |
|
|
41 |
#include <sys/libkern.h> |
| 41 |
|
42 |
|
|
|
43 |
#include <netipx/ipx.h> |
| 42 |
#include <netipx/ipx_var.h> |
44 |
#include <netipx/ipx_var.h> |
| 43 |
|
45 |
|
| 44 |
/* |
|
|
| 45 |
* Checksum routine for Network Systems Protocol Packets (Big-Endian). |
| 46 |
* |
| 47 |
* This routine is very heavily used in the network |
| 48 |
* code and should be modified for each CPU to be as fast as possible. |
| 49 |
*/ |
| 50 |
|
46 |
|
| 51 |
#define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } |
47 |
#define SUMADV sum += *w++ |
| 52 |
#define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} |
|
|
| 53 |
|
48 |
|
| 54 |
u_short |
49 |
u_short |
| 55 |
ipx_cksum(m, len) |
50 |
ipx_cksum(struct mbuf *m, int len) { |
| 56 |
struct mbuf *m; |
51 |
u_int32_t sum = 0; |
| 57 |
int len; |
52 |
u_short *w; |
| 58 |
{ |
53 |
u_char oldtc; |
| 59 |
register u_short *w; |
54 |
int mlen, words; |
| 60 |
register int sum = 0; |
55 |
struct ipx *ipx; |
| 61 |
register int mlen = 0; |
|
|
| 62 |
register int sum2; |
| 63 |
|
| 64 |
union { |
56 |
union { |
| 65 |
u_short s[2]; |
57 |
u_char b[2]; |
| 66 |
long l; |
58 |
u_short w; |
| 67 |
} l_util; |
59 |
} buf; |
| 68 |
|
60 |
|
| 69 |
for (;m != NULL && len; m = m->m_next) { |
61 |
ipx = mtod(m, struct ipx*); |
| 70 |
if (m->m_len == 0) |
62 |
oldtc = ipx->ipx_tc; |
| 71 |
continue; |
63 |
ipx->ipx_tc = 0; |
| 72 |
/* |
64 |
w = &ipx->ipx_len; |
| 73 |
* Each trip around loop adds in |
65 |
len -= 2; |
| 74 |
* word from one mbuf segment. |
66 |
mlen = 2; |
| 75 |
*/ |
67 |
|
| 76 |
w = mtod(m, u_short *); |
68 |
for(;;) { |
| 77 |
if (mlen == -1) { |
69 |
mlen = imin(m->m_len - mlen, len); |
| 78 |
/* |
70 |
words = mlen / 2; |
| 79 |
* There is a byte left from the last segment; |
71 |
len -= mlen & ~1; |
| 80 |
* ones-complement add it into the checksum. |
72 |
while (words >= 16) { |
| 81 |
*/ |
73 |
SUMADV; SUMADV; SUMADV; SUMADV; |
| 82 |
#if BYTE_ORDER == BIG_ENDIAN |
74 |
SUMADV; SUMADV; SUMADV; SUMADV; |
| 83 |
sum += *(u_char *)w; |
75 |
SUMADV; SUMADV; SUMADV; SUMADV; |
| 84 |
#else |
76 |
SUMADV; SUMADV; SUMADV; SUMADV; |
| 85 |
sum += *(u_char *)w << 8; |
77 |
words -= 16; |
| 86 |
#endif |
78 |
} |
| 87 |
sum += sum; |
79 |
while (words--) |
| 88 |
w = (u_short *)(1 + (char *)w); |
80 |
SUMADV; |
| 89 |
mlen = m->m_len - 1; |
81 |
if (len == 0) |
| 90 |
len--; |
82 |
break; |
| 91 |
FOLD(sum); |
83 |
mlen &= 1; |
| 92 |
} else |
84 |
if (mlen) { |
| 93 |
mlen = m->m_len; |
85 |
buf.b[0] = *(u_char*)w; |
| 94 |
if (len < mlen) |
86 |
if (--len == 0) { |
| 95 |
mlen = len; |
87 |
buf.b[1] = 0; |
| 96 |
len -= mlen; |
88 |
sum += buf.w; |
| 97 |
/* |
89 |
break; |
| 98 |
* We can do a 16 bit ones complement sum using |
90 |
} |
| 99 |
* 32 bit arithmetic registers for adding, |
91 |
} |
| 100 |
* with carries from the low added |
92 |
m = m->m_next; |
| 101 |
* into the high (by normal carry-chaining) |
93 |
if (m == NULL) |
| 102 |
* so long as we fold back before 16 carries have occured. |
94 |
break; |
| 103 |
*/ |
95 |
w = mtod(m, u_short*); |
| 104 |
if (1 & (int) w) |
96 |
if (mlen) { |
| 105 |
goto uuuuglyy; |
97 |
buf.b[1] = *(u_char*)w; |
| 106 |
#ifndef TINY |
98 |
sum += buf.w; |
| 107 |
/* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ |
99 |
((u_char*)w)++; |
| 108 |
while ((mlen -= 32) >= 0) { |
100 |
if (--len == 0) |
| 109 |
sum += w[0]; sum += sum; sum += w[1]; sum += sum; |
101 |
break; |
| 110 |
sum += w[2]; sum += sum; sum += w[3]; sum += sum; |
102 |
} |
| 111 |
sum += w[4]; sum += sum; sum += w[5]; sum += sum; |
|
|
| 112 |
sum += w[6]; sum += sum; sum += w[7]; sum += sum; |
| 113 |
FOLD(sum); |
| 114 |
sum += w[8]; sum += sum; sum += w[9]; sum += sum; |
| 115 |
sum += w[10]; sum += sum; sum += w[11]; sum += sum; |
| 116 |
sum += w[12]; sum += sum; sum += w[13]; sum += sum; |
| 117 |
sum += w[14]; sum += sum; sum += w[15]; sum += sum; |
| 118 |
FOLD(sum); |
| 119 |
w += 16; |
| 120 |
} |
| 121 |
mlen += 32; |
| 122 |
#endif |
| 123 |
while ((mlen -= 8) >= 0) { |
| 124 |
sum += w[0]; sum += sum; sum += w[1]; sum += sum; |
| 125 |
sum += w[2]; sum += sum; sum += w[3]; sum += sum; |
| 126 |
FOLD(sum); |
| 127 |
w += 4; |
| 128 |
} |
| 129 |
mlen += 8; |
| 130 |
while ((mlen -= 2) >= 0) { |
| 131 |
sum += *w++; sum += sum; |
| 132 |
} |
| 133 |
goto commoncase; |
| 134 |
uuuuglyy: |
| 135 |
#if BYTE_ORDER == BIG_ENDIAN |
| 136 |
#define ww(n) (((u_char *)w)[n + n + 1]) |
| 137 |
#define vv(n) (((u_char *)w)[n + n]) |
| 138 |
#else |
| 139 |
#if BYTE_ORDER == LITTLE_ENDIAN |
| 140 |
#define vv(n) (((u_char *)w)[n + n + 1]) |
| 141 |
#define ww(n) (((u_char *)w)[n + n]) |
| 142 |
#endif |
| 143 |
#endif |
| 144 |
sum2 = 0; |
| 145 |
#ifndef TINY |
| 146 |
while ((mlen -= 32) >= 0) { |
| 147 |
sum += ww(0); sum += sum; sum += ww(1); sum += sum; |
| 148 |
sum += ww(2); sum += sum; sum += ww(3); sum += sum; |
| 149 |
sum += ww(4); sum += sum; sum += ww(5); sum += sum; |
| 150 |
sum += ww(6); sum += sum; sum += ww(7); sum += sum; |
| 151 |
FOLD(sum); |
| 152 |
sum += ww(8); sum += sum; sum += ww(9); sum += sum; |
| 153 |
sum += ww(10); sum += sum; sum += ww(11); sum += sum; |
| 154 |
sum += ww(12); sum += sum; sum += ww(13); sum += sum; |
| 155 |
sum += ww(14); sum += sum; sum += ww(15); sum += sum; |
| 156 |
FOLD(sum); |
| 157 |
sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; |
| 158 |
sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; |
| 159 |
sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; |
| 160 |
sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; |
| 161 |
FOLD(sum2); |
| 162 |
sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; |
| 163 |
sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; |
| 164 |
sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; |
| 165 |
sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; |
| 166 |
FOLD(sum2); |
| 167 |
w += 16; |
| 168 |
} |
| 169 |
mlen += 32; |
| 170 |
#endif |
| 171 |
while ((mlen -= 8) >= 0) { |
| 172 |
sum += ww(0); sum += sum; sum += ww(1); sum += sum; |
| 173 |
sum += ww(2); sum += sum; sum += ww(3); sum += sum; |
| 174 |
FOLD(sum); |
| 175 |
sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; |
| 176 |
sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; |
| 177 |
FOLD(sum2); |
| 178 |
w += 4; |
| 179 |
} |
| 180 |
mlen += 8; |
| 181 |
while ((mlen -= 2) >= 0) { |
| 182 |
sum += ww(0); sum += sum; |
| 183 |
sum2 += vv(0); sum2 += sum2; |
| 184 |
w++; |
| 185 |
} |
| 186 |
sum += (sum2 << 8); |
| 187 |
commoncase: |
| 188 |
if (mlen == -1) { |
| 189 |
#if BYTE_ORDER == BIG_ENDIAN |
| 190 |
sum += *(u_char *)w << 8; |
| 191 |
#else |
| 192 |
sum += *(u_char *)w; |
| 193 |
#endif |
| 194 |
} |
| 195 |
FOLD(sum); |
| 196 |
} |
| 197 |
if (mlen == -1) { |
| 198 |
/* We had an odd number of bytes to sum; assume a garbage |
| 199 |
byte of zero and clean up */ |
| 200 |
sum += sum; |
| 201 |
FOLD(sum); |
| 202 |
} |
103 |
} |
| 203 |
/* |
104 |
|
| 204 |
* sum has already been kept to low sixteen bits. |
105 |
ipx->ipx_tc = oldtc; |
| 205 |
* just examine result and exit. |
106 |
|
| 206 |
*/ |
107 |
sum = (sum & 0xffff) + (sum >> 16); |
| 207 |
if(sum == 0xffff) |
108 |
if (sum >= 0x10000) |
| 208 |
sum = 0; |
109 |
sum++; |
|
|
110 |
if (sum) |
| 111 |
sum = ~sum; |
| 209 |
return (sum); |
112 |
return (sum); |
| 210 |
} |
113 |
} |