Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
0880b18e | 2 | * Copyright (c) 1985, 1986 Regents of the University of California. |
5f7901a4 | 3 | * All rights reserved. |
da7c5cc6 | 4 | * |
5f7901a4 | 5 | * Redistribution and use in source and binary forms are permitted |
616d42db KB |
6 | * provided that the above copyright notice and this paragraph are |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
5f7901a4 | 16 | * |
ca67e7b4 | 17 | * @(#)ns_cksum.c 7.3 (Berkeley) 6/29/88 |
da7c5cc6 | 18 | */ |
5f7901a4 | 19 | |
c43137cc KS |
20 | #include "types.h" |
21 | #include "mbuf.h" | |
47d988e7 | 22 | |
47d988e7 KS |
23 | |
24 | /* | |
25 | * Checksum routine for Network Systems Protocol Packets (VAX Version). | |
26 | * | |
27 | * This routine is very heavily used in the network | |
28 | * code and should be modified for each CPU to be as fast as possible. | |
29 | */ | |
2ef559c8 | 30 | |
47d988e7 KS |
31 | u_short |
32 | ns_cksum(m, len) | |
33 | register struct mbuf *m; | |
34 | register int len; | |
35 | { | |
36 | register u_short *w; /* on vax, known to be r9 */ | |
37 | register int sum = 0; /* on vax, known to be r8 */ | |
38 | register int low = 0; /* on vax, known to be r7 */ | |
cc6b1d0f | 39 | register int mlen = low; /* want 0, shuts lint up about low */ |
47d988e7 KS |
40 | |
41 | for (;;) { | |
42 | /* | |
43 | * Each trip around loop adds in | |
44 | * word from one mbuf segment. | |
45 | */ | |
46 | w = mtod(m, u_short *); | |
47 | if (mlen == -1) { | |
48 | /* | |
49 | * There is a byte left from the last segment; | |
50 | * add it into the checksum. Don't have to worry | |
2ef559c8 KS |
51 | * about a carry-out here because we make sure |
52 | * that high part of (32 bit) sum is small below. | |
47d988e7 KS |
53 | */ |
54 | sum += *(u_char *)w << 8; | |
55 | sum += sum; | |
56 | w = (u_short *)((char *)w + 1); | |
57 | mlen = m->m_len - 1; | |
58 | len--; | |
59 | } else | |
60 | mlen = m->m_len; | |
61 | m = m->m_next; | |
62 | if (len < mlen) | |
63 | mlen = len; | |
64 | len -= mlen; | |
65 | /* | |
2ef559c8 KS |
66 | * Force to long boundary so we do longword aligned |
67 | * memory operations. It is too hard to do byte | |
68 | * adjustment, do only word adjustment. | |
69 | */ | |
70 | if (((int)w&0x2) && mlen >= 2) { | |
71 | sum += *w++; | |
72 | sum += sum; | |
73 | mlen -= 2; | |
74 | } | |
75 | /* | |
47d988e7 | 76 | * |
2ef559c8 KS |
77 | * We can do a 16 bit ones complement sum using |
78 | * 32 bit arithmetic registers for adding, | |
79 | * with carries from the low added | |
80 | * into the high (by normal carry-chaining) | |
81 | * so long as we fold back before 16 carries have occured. | |
47d988e7 KS |
82 | * |
83 | */ | |
84 | while ((mlen -= 32) >= 0) { | |
2ef559c8 | 85 | /*asm("bicpsw $1"); clears carry */ |
47d988e7 KS |
86 | #undef ADD |
87 | #define ADD asm("movw (r9)+,r7")asm("addl2 r7,r8")asm("addl2 r8,r8") | |
88 | #define FOLD { asm("ashl $-16,r8,r0")asm(" addw2 r0,r8"); \ | |
89 | asm("adwc $0,r8")asm(" movzwl r8,r8"); } | |
90 | FOLD; | |
91 | ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD; | |
92 | FOLD; | |
93 | ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD; | |
94 | } | |
95 | mlen += 32; | |
2ef559c8 KS |
96 | while ((mlen -= 8) >= 0) { |
97 | /*asm("bicpsw $1"); clears carry */ | |
47d988e7 | 98 | FOLD; |
2ef559c8 | 99 | ADD; ADD; ADD; ADD; |
47d988e7 | 100 | } |
2ef559c8 | 101 | mlen += 8; |
47d988e7 KS |
102 | /* |
103 | * Now eliminate the possibility of carry-out's by | |
104 | * folding back to a 16 bit number (adding high and | |
105 | * low parts together.) Then mop up trailing words | |
2ef559c8 | 106 | * and maybe an odd byte. |
47d988e7 KS |
107 | */ |
108 | FOLD; | |
109 | while ((mlen -= 2) >= 0) { | |
110 | ADD; | |
111 | } | |
112 | if (mlen == -1) { | |
113 | sum += *(u_char *)w; | |
114 | } | |
115 | if (len == 0) | |
116 | break; | |
117 | /* | |
118 | * Locate the next block with some data. | |
119 | * If there is a word split across a boundary we | |
120 | * will wrap to the top with mlen == -1 and | |
121 | * then add it in shifted appropriately. | |
122 | */ | |
123 | for (;;) { | |
124 | if (m == 0) { | |
2ef559c8 | 125 | printf("idpcksum: out of data\n"); |
47d988e7 KS |
126 | goto done; |
127 | } | |
128 | if (m->m_len) | |
129 | break; | |
130 | m = m->m_next; | |
131 | } | |
132 | } | |
133 | done: | |
134 | /* | |
135 | * Add together high and low parts of sum | |
136 | * and carry to get cksum. | |
137 | * Have to be careful to not drop the last | |
138 | * carry here. | |
139 | */ | |
140 | FOLD; | |
2ef559c8 | 141 | |
47d988e7 | 142 | if(sum==0xffff) sum = 0; |
2ef559c8 | 143 | return (sum); |
47d988e7 | 144 | } |