Commit | Line | Data |
---|---|---|
fcfe450e | 1 | /* in_cksum.c 1.13 82/10/09 */ |
51041fae BJ |
2 | |
3 | #include <sys/types.h> | |
dad64fdf | 4 | #include "../h/mbuf.h" |
fcfe450e BJ |
5 | #include "../netinet/in.h" |
6 | #include "../netinet/in_systm.h" | |
51041fae BJ |
7 | |
8 | /* | |
2b4b57cd BJ |
9 | * Checksum routine for Internet Protocol family headers. |
10 | * This routine is very heavily used in the network | |
11 | * code and should be rewritten for each CPU to be as fast as possible. | |
51041fae | 12 | */ |
51041fae | 13 | |
2b4b57cd | 14 | #if vax |
8a13b737 | 15 | in_cksum(m, len) |
51041fae BJ |
16 | register struct mbuf *m; |
17 | register int len; | |
18 | { | |
2b4b57cd | 19 | register u_short *w; /* known to be r9 */ |
51041fae BJ |
20 | register int sum = 0; /* known to be r8 */ |
21 | register int mlen = 0; | |
51041fae BJ |
22 | |
23 | for (;;) { | |
2b4b57cd BJ |
24 | /* |
25 | * Each trip around loop adds in | |
26 | * word from one mbuf segment. | |
27 | */ | |
28 | w = mtod(m, u_short *); | |
51041fae | 29 | if (mlen == -1) { |
2b4b57cd BJ |
30 | /* |
31 | * There is a byte left from the last segment; | |
32 | * add it into the checksum. Don't have to worry | |
33 | * about a carry-out here because we make sure | |
34 | * that high part of (32 bit) sum is small below. | |
35 | */ | |
51041fae | 36 | sum += *(u_char *)w << 8; |
e6dd2097 | 37 | w = (u_short *)((char *)w + 1); |
51041fae BJ |
38 | mlen = m->m_len - 1; |
39 | len--; | |
40 | } else | |
41 | mlen = m->m_len; | |
42 | m = m->m_next; | |
43 | if (len < mlen) | |
44 | mlen = len; | |
45 | len -= mlen; | |
2b4b57cd BJ |
46 | /* |
47 | * Force to long boundary so we do longword aligned | |
48 | * memory operations. It is too hard to do byte | |
49 | * adjustment, do only word adjustment. | |
50 | */ | |
51 | if (((int)w&0x2) && mlen >= 2) { | |
52 | sum += *w++; | |
53 | mlen -= 2; | |
54 | } | |
55 | /* | |
56 | * Do as much of the checksum as possible 32 bits at at time. | |
57 | * In fact, this loop is unrolled to make overhead from | |
58 | * branches &c small. | |
59 | * | |
60 | * We can do a 16 bit ones complement sum 32 bits at a time | |
61 | * because the 32 bit register is acting as two 16 bit | |
62 | * registers for adding, with carries from the low added | |
63 | * into the high (by normal carry-chaining) and carries | |
64 | * from the high carried into the low on the next word | |
65 | * by use of the adwc instruction. This lets us run | |
66 | * this loop at almost memory speed. | |
67 | * | |
68 | * Here there is the danger of high order carry out, and | |
69 | * we carefully use adwc. | |
70 | */ | |
51041fae | 71 | while ((mlen -= 32) >= 0) { |
4d0a6cbd BJ |
72 | asm("clrl r0"); /* clears carry */ |
73 | #undef ADD | |
74 | #define ADD asm("adwc (r9)+,r8;"); | |
51041fae | 75 | ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD; |
4d0a6cbd | 76 | asm("adwc $0,r8"); |
51041fae BJ |
77 | } |
78 | mlen += 32; | |
79 | while ((mlen -= 8) >= 0) { | |
4d0a6cbd BJ |
80 | asm("clrl r0"); |
81 | ADD; ADD; | |
82 | asm("adwc $0,r8"); | |
51041fae BJ |
83 | } |
84 | mlen += 8; | |
2b4b57cd BJ |
85 | /* |
86 | * Now eliminate the possibility of carry-out's by | |
87 | * folding back to a 16 bit number (adding high and | |
88 | * low parts together.) Then mop up trailing words | |
89 | * and maybe an odd byte. | |
90 | */ | |
91 | { asm("ashl $-16,r8,r0; addw2 r0,r8"); | |
92 | asm("adwc $0,r8; movzwl r8,r8"); } | |
51041fae | 93 | while ((mlen -= 2) >= 0) { |
2b4b57cd | 94 | asm("movzwl (r9)+,r0; addl2 r0,r8"); |
51041fae BJ |
95 | } |
96 | if (mlen == -1) | |
97 | sum += *(u_char *)w; | |
98 | if (len == 0) | |
99 | break; | |
2b4b57cd BJ |
100 | /* |
101 | * Locate the next block with some data. | |
102 | * If there is a word split across a boundary we | |
103 | * will wrap to the top with mlen == -1 and | |
104 | * then add it in shifted appropriately. | |
105 | */ | |
51041fae | 106 | for (;;) { |
f248b7ed | 107 | if (m == 0) { |
e6dd2097 | 108 | printf("cksum: out of data\n"); |
f248b7ed BJ |
109 | goto done; |
110 | } | |
51041fae BJ |
111 | if (m->m_len) |
112 | break; | |
113 | m = m->m_next; | |
114 | } | |
115 | } | |
f248b7ed | 116 | done: |
2b4b57cd BJ |
117 | /* |
118 | * Add together high and low parts of sum | |
119 | * and carry to get cksum. | |
120 | * Have to be careful to not drop the last | |
121 | * carry here. | |
122 | */ | |
e6dd2097 BJ |
123 | { asm("ashl $-16,r8,r0; addw2 r0,r8; adwc $0,r8"); |
124 | asm("mcoml r8,r8; movzwl r8,r8"); } | |
125 | return (sum); | |
51041fae | 126 | } |
2b4b57cd | 127 | #endif |