1 /* 2 * Copyright (c) 1982, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)in_cksum.c 7.6 (Berkeley) 12/16/90 8 */ 9 10 #include "sys/param.h" 11 #include "sys/mbuf.h" 12 13 /* 14 * Checksum routine for Internet Protocol family headers (CCI Version). 15 * 16 * This routine is very heavily used in the network 17 * code and should be modified for each CPU to be as fast as possible. 18 */ 19 20 #define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } 21 #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} 22 23 #define ADD(n) asm("adwc n (r10),r9") 24 #define MOP asm("adwc $0,r9") 25 #define BOTCH asm("addl2 r7,r9") 26 27 in_cksum(m, len) 28 register struct mbuf *m; 29 register int len; 30 { 31 register u_short *w; /* On CCI, known to be r10 */ 32 register int sum = 0; /* On CCI, known to be r9 */ 33 register int mlen = 0; 34 #ifndef lint 35 register int ClearCarry = 0; /* On CCI, known to be r7; see BOTCH */ 36 #endif 37 int byte_swapped = 0; 38 39 union { 40 char c[2]; 41 u_short s; 42 } s_util; 43 union { 44 u_short s[2]; 45 long l; 46 } l_util; 47 48 for (;m && len; m = m->m_next) { 49 if (m->m_len == 0) 50 continue; 51 w = mtod(m, u_short *); 52 if (mlen == -1) { 53 /* 54 * The first byte of this mbuf is the continuation 55 * of a word spanning between this mbuf and the 56 * last mbuf. 57 * 58 * s_util.c[0] is already saved when scanning previous 59 * mbuf. sum was REDUCEd when we found mlen == -1. 60 */ 61 s_util.c[1] = *(char *)w; 62 sum += s_util.s; 63 w = (u_short *)((char *)w + 1); 64 mlen = m->m_len - 1; 65 len--; 66 } else 67 mlen = m->m_len; 68 if (len < mlen) 69 mlen = len; 70 len -= mlen; 71 /* 72 * Force to long boundary so we do longword aligned 73 * memory operations. 74 */ 75 if (3 & (int) w) { 76 REDUCE; 77 if ((1 & (int) w) && (mlen > 0)) { 78 sum <<= 8; 79 s_util.c[0] = *(char *)w; 80 w = (u_short *)((char *)w + 1); 81 mlen--; 82 byte_swapped = 1; 83 } 84 if ((2 & (int) w) && (mlen >= 2)) { 85 sum += *w++; 86 mlen -= 2; 87 } 88 } 89 /* 90 * Do as much of the checksum as possible 32 bits at at time. 91 * In fact, this loop is unrolled to make overhead from 92 * branches &c small. 93 */ 94 while ((mlen -= 32) >= 0) { 95 /* 96 * The loop construct clears carry for us 97 * on vaxen, however, on the CCI machine subtracting 98 * a small postive number from a larger one doesn't. 99 * 100 * Doing a bicpsw is very slow (slows down the routine 101 * by a factor of 2); explicitly adding an immediate 102 * 0 to a register is optimized out; so we fake out 103 * the optimizer and add a register whose contents 104 * is always zero. 105 */ 106 BOTCH; 107 ADD(0); ADD(4); ADD(8); ADD(12); 108 ADD(16); ADD(20); ADD(24); ADD(28); 109 MOP; w += 16; 110 } 111 mlen += 32; 112 while ((mlen -= 8) >= 0) { 113 BOTCH; 114 ADD(0); ADD(4); 115 MOP; 116 w += 4; 117 } 118 mlen += 8; 119 if (mlen == 0 && byte_swapped == 0) 120 continue; /* worth 1% maybe ?? */ 121 REDUCE; 122 while ((mlen -= 2) >= 0) { 123 sum += *w++; 124 } 125 if (byte_swapped) { 126 sum <<= 8; 127 byte_swapped = 0; 128 if (mlen == -1) { 129 s_util.c[1] = *(char *)w; 130 sum += s_util.s; 131 mlen = 0; 132 } else 133 mlen = -1; 134 } else if (mlen == -1) 135 /* 136 * This mbuf has odd number of bytes. 137 * There could be a word split betwen 138 * this mbuf and the next mbuf. 139 * Save the last byte (to prepend to next mbuf). 140 */ 141 s_util.c[0] = *(char *)w; 142 } 143 if (len) 144 printf("cksum: out of data\n"); 145 if (mlen == -1) { 146 /* The last mbuf has odd # of bytes. Follow the 147 standard (the odd byte is shifted left by 8 bits) */ 148 s_util.c[1] = 0; 149 sum += s_util.s; 150 } 151 REDUCE; 152 return (~sum & 0xffff); 153 } 154