1 /* in_cksum.c 6.1 83/07/29 */ 2 3 #include "../h/types.h" 4 #include "../h/mbuf.h" 5 #include "../netinet/in.h" 6 #include "../netinet/in_systm.h" 7 8 #if defined(tahoe) 9 /* 10 * Checksum routine for Internet Protocol family headers. 11 * 12 * This routine is very heavily used in the network 13 * code and should be modified for each CPU to be as fast as possible. 14 * 15 * This implementation is TAHOE version. 16 */ 17 18 #undef ADDCARRY 19 #define ADDCARRY(sum) { \ 20 if (sum & 0xffff0000) { \ 21 sum &= 0xffff; \ 22 sum++; \ 23 } \ 24 } 25 in_cksum(m, len) 26 register struct mbuf *m; 27 register int len; 28 { 29 union word { 30 char c[2]; 31 u_short s; 32 } u; 33 register u_short *w; 34 register int sum = 0; 35 register int mlen = 0; 36 37 for (;m && len; m = m->m_next) { 38 39 if (m->m_len == 0) { 40 continue; 41 } 42 43 w = mtod(m, u_short *); 44 if (mlen == -1) { 45 /* 46 * The first byte of this mbuf is the continuation 47 * of a word spanning between this mbuf and the 48 * last mbuf. 49 */ 50 51 /* u.c[0] is already saved when scanning previous 52 * mbuf. 53 */ 54 u.c[1] = *(u_char *)w; 55 sum += u.s; 56 ADDCARRY(sum); 57 58 w = (u_short *)((char *)w + 1); 59 mlen = m->m_len - 1; 60 len--; 61 } else 62 mlen = m->m_len; 63 64 if (len < mlen) 65 mlen = len; 66 len -= mlen; 67 68 /* 69 * add by words. 70 */ 71 while ((mlen -= 2) >= 0) { 72 73 if ((int)w & 0x1) { 74 /* word is not aligned */ 75 u.c[0] = *(char *)w; 76 u.c[1] = *((char *)w+1); 77 sum += u.s; 78 w++; 79 } 80 else { 81 sum += *w++; 82 } 83 ADDCARRY(sum); 84 } 85 if (mlen == -1) { 86 /* 87 * This mbuf has odd number of bytes. 88 * There could be a word split betwen 89 * this mbuf and the next mbuf. 90 * Save the last byte (to prepend to next mbuf). 91 */ 92 u.c[0] = *(u_char *)w; 93 } 94 } 95 if (len) 96 printf("cksum: out of data\n"); 97 if (mlen == -1) { 98 /* The last mbuf has odd # of bytes. Follow the 99 standard (the odd byte is shifted left by 8 bits) */ 100 u.c[1] = 0; 101 sum += u.s; 102 ADDCARRY(sum); 103 } 104 done: 105 return (~sum & 0xffff); 106 } 107 #endif 108 109 #if defined(vax) 110 111 /* 112 * Checksum routine for Internet Protocol family headers (VAX Version). 113 * 114 * This routine is very heavily used in the network 115 * code and should be modified for each CPU to be as fast as possible. 116 */ 117 118 in_cksum(m, len) 119 register struct mbuf *m; 120 register int len; 121 { 122 register u_short *w; /* on Tahoe, known to be r10 */ 123 register int sum = 0; /* on Tahoe, known to be r9 */ 124 register int mlen = 0; 125 126 for (;;) { 127 /* 128 * Each trip around loop adds in 129 * word from one mbuf segment. 130 */ 131 w = mtod(m, u_short *); 132 if (mlen == -1) { 133 /* 134 * There is a byte left from the last segment; 135 * add it into the checksum. Don't have to worry 136 * about a carry-out here because we make sure 137 * that high part of (32 bit) sum is small below. 138 */ 139 sum += *(u_char *)w << 8; 140 w = (u_short *)((char *)w + 1); 141 mlen = m->m_len - 1; 142 len--; 143 } else 144 mlen = m->m_len; 145 m = m->m_next; 146 if (len < mlen) 147 mlen = len; 148 len -= mlen; 149 /* 150 * Force to long boundary so we do longword aligned 151 * memory operations. 152 */ 153 if (((int)w&0x1) && mlen >= 1) { 154 sum += *(u_char *)w++; 155 mlen -= 1; 156 } 157 if (((int)w&0x2) && mlen >= 2) { 158 sum += *w++; 159 mlen -= 2; 160 } 161 /* 162 * Do as much of the checksum as possible 32 bits at at time. 163 * In fact, this loop is unrolled to make overhead from 164 * branches &c small. 165 * 166 * We can do a 16 bit ones complement sum 32 bits at a time 167 * because the 32 bit register is acting as two 16 bit 168 * registers for adding, with carries from the low added 169 * into the high (by normal carry-chaining) and carries 170 * from the high carried into the low on the next word 171 * by use of the adwc instruction. This lets us run 172 * this loop at almost memory speed. 173 * 174 * Here there is the danger of high order carry out, and 175 * we carefully use adwc. 176 */ 177 while ((mlen -= 32) >= 0) { 178 #undef ADD 179 asm("clrl r0"); /* clears carry */ 180 #define ADD asm("adwc (r10),r9;addl2 $4,r10; "); 181 ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD; 182 asm("adwc $0,r9"); 183 } 184 mlen += 32; 185 while ((mlen -= 8) >= 0) { 186 asm("clrl r0"); 187 ADD; ADD; 188 asm("adwc $0,r9"); 189 } 190 mlen += 8; 191 /* 192 * Now eliminate the possibility of carry-out's by 193 * folding back to a 16 bit number (adding high and 194 * low parts together.) Then mop up trailing words 195 * and maybe an odd byte. 196 */ 197 { asm("shal $-16,r9,r0; addw2 r0,r9"); 198 asm("adwc $0,r9; movzwl r9,r9"); } 199 while ((mlen -= 2) >= 0) { 200 asm("movzwl (r10),r0;addl2 $4,r10; addl2 r0,r9"); 201 } 202 if (mlen == -1) { 203 sum += *(u_char *)w; 204 } 205 if (len == 0) 206 break; 207 /* 208 * Locate the next block with some data. 209 * If there is a word split across a boundary we 210 * will wrap to the top with mlen == -1 and 211 * then add it in shifted appropriately. 212 */ 213 for (;;) { 214 if (m == 0) { 215 printf("cksum: out of data\n"); 216 goto done; 217 } 218 if (m->m_len) 219 break; 220 m = m->m_next; 221 } 222 } 223 done: 224 /* 225 * Add together high and low parts of sum 226 * and carry to get cksum. 227 * Have to be careful to not drop the last 228 * carry here. 229 */ 230 { asm("shal $-16,r9,r0; addw2 r0,r9; adwc $0,r9"); 231 asm("mcoml r9,r9; movzwl r9,r9"); } 232 return (sum); 233 } 234 #endif 235