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