1 /*
2 * Copyright (c) 1985, 1986 Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)ns_cksum.c 7.6 (Berkeley) 12/16/90
8 */
9
10 #include "sys/param.h"
11 #include "sys/mbuf.h"
12
13
14 /*
15 * Checksum routine for Network Systems Protocol Packets (VAX Version).
16 *
17 * This routine is very heavily used in the network
18 * code and should be modified for each CPU to be as fast as possible.
19 */
20
21 u_short
ns_cksum(m,len)22 ns_cksum(m, len)
23 register struct mbuf *m;
24 register int len;
25 {
26 register u_short *w; /* on vax, known to be r9 */
27 register int sum = 0; /* on vax, known to be r8 */
28 register int low = 0; /* on vax, known to be r7 */
29 register int mlen = low; /* want 0, shuts lint up about low */
30
31 for (;;) {
32 /*
33 * Each trip around loop adds in
34 * word from one mbuf segment.
35 */
36 w = mtod(m, u_short *);
37 if (mlen == -1) {
38 /*
39 * There is a byte left from the last segment;
40 * add it into the checksum. Don't have to worry
41 * about a carry-out here because we make sure
42 * that high part of (32 bit) sum is small below.
43 */
44 sum += *(u_char *)w << 8;
45 sum += sum;
46 w = (u_short *)((char *)w + 1);
47 mlen = m->m_len - 1;
48 len--;
49 } else
50 mlen = m->m_len;
51 m = m->m_next;
52 if (len < mlen)
53 mlen = len;
54 len -= mlen;
55 /*
56 * Force to long boundary so we do longword aligned
57 * memory operations. It is too hard to do byte
58 * adjustment, do only word adjustment.
59 */
60 if (((int)w&0x2) && mlen >= 2) {
61 sum += *w++;
62 sum += sum;
63 mlen -= 2;
64 }
65 /*
66 *
67 * We can do a 16 bit ones complement sum using
68 * 32 bit arithmetic registers for adding,
69 * with carries from the low added
70 * into the high (by normal carry-chaining)
71 * so long as we fold back before 16 carries have occured.
72 *
73 */
74 while ((mlen -= 32) >= 0) {
75 /*asm("bicpsw $1"); clears carry */
76 #undef ADD
77 #define ADD asm("movw (r9)+,r7")asm("addl2 r7,r8")asm("addl2 r8,r8")
78 #define FOLD { asm("ashl $-16,r8,r0")asm(" addw2 r0,r8"); \
79 asm("adwc $0,r8")asm(" movzwl r8,r8"); }
80 FOLD;
81 ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD;
82 FOLD;
83 ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD;
84 }
85 mlen += 32;
86 while ((mlen -= 8) >= 0) {
87 /*asm("bicpsw $1"); clears carry */
88 FOLD;
89 ADD; ADD; ADD; ADD;
90 }
91 mlen += 8;
92 /*
93 * Now eliminate the possibility of carry-out's by
94 * folding back to a 16 bit number (adding high and
95 * low parts together.) Then mop up trailing words
96 * and maybe an odd byte.
97 */
98 FOLD;
99 while ((mlen -= 2) >= 0) {
100 ADD;
101 }
102 if (mlen == -1) {
103 sum += *(u_char *)w;
104 }
105 if (len == 0)
106 break;
107 /*
108 * Locate the next block with some data.
109 * If there is a word split across a boundary we
110 * will wrap to the top with mlen == -1 and
111 * then add it in shifted appropriately.
112 */
113 for (;;) {
114 if (m == 0) {
115 printf("idpcksum: out of data\n");
116 goto done;
117 }
118 if (m->m_len)
119 break;
120 m = m->m_next;
121 }
122 }
123 done:
124 /*
125 * Add together high and low parts of sum
126 * and carry to get cksum.
127 * Have to be careful to not drop the last
128 * carry here.
129 */
130 FOLD;
131
132 if(sum==0xffff) sum = 0;
133 return (sum);
134 }
135