1 /* 2 * Copyright (c) 1988, 1992 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)in_cksum.c 7.4 (Berkeley) 03/02/92 8 */ 9 10 #include "param.h" 11 #include "mbuf.h" 12 13 /* 14 * Checksum routine for Internet Protocol family headers (Portable 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) (x > 65535 ? x -= 65535 : x) 21 #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} 22 23 in_cksum(m, len) 24 register struct mbuf *m; 25 register int len; 26 { 27 register u_short *w; 28 register int sum = 0; 29 register int mlen = 0; 30 int byte_swapped = 0; 31 32 union { 33 char c[2]; 34 u_short s; 35 } s_util; 36 union { 37 u_short s[2]; 38 long l; 39 } l_util; 40 41 for (;m && len; m = m->m_next) { 42 if (m->m_len == 0) 43 continue; 44 w = mtod(m, u_short *); 45 if (mlen == -1) { 46 /* 47 * The first byte of this mbuf is the continuation 48 * of a word spanning between this mbuf and the 49 * last mbuf. 50 * 51 * s_util.c[0] is already saved when scanning previous 52 * mbuf. 53 */ 54 s_util.c[1] = *(char *)w; 55 sum += s_util.s; 56 w = (u_short *)((char *)w + 1); 57 mlen = m->m_len - 1; 58 len--; 59 } else 60 mlen = m->m_len; 61 if (len < mlen) 62 mlen = len; 63 len -= mlen; 64 /* 65 * Force to even boundary. 66 */ 67 if ((1 & (int) w) && (mlen > 0)) { 68 REDUCE; 69 sum <<= 8; 70 s_util.c[0] = *(u_char *)w; 71 w = (u_short *)((char *)w + 1); 72 mlen--; 73 byte_swapped = 1; 74 } 75 /* 76 * Unroll the loop to make overhead from 77 * branches &c small. 78 */ 79 while ((mlen -= 32) >= 0) { 80 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 81 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 82 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 83 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 84 w += 16; 85 } 86 mlen += 32; 87 while ((mlen -= 8) >= 0) { 88 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 89 w += 4; 90 } 91 mlen += 8; 92 if (mlen == 0 && byte_swapped == 0) 93 continue; 94 REDUCE; 95 while ((mlen -= 2) >= 0) { 96 sum += *w++; 97 } 98 if (byte_swapped) { 99 REDUCE; 100 sum <<= 8; 101 byte_swapped = 0; 102 if (mlen == -1) { 103 s_util.c[1] = *(char *)w; 104 sum += s_util.s; 105 mlen = 0; 106 } else 107 mlen = -1; 108 } else if (mlen == -1) 109 s_util.c[0] = *(char *)w; 110 } 111 if (len) 112 printf("cksum: out of data\n"); 113 if (mlen == -1) { 114 /* The last mbuf has odd # of bytes. Follow the 115 standard (the odd byte may be shifted left by 8 bits 116 or not as determined by endian-ness of the machine) */ 117 s_util.c[1] = 0; 118 sum += s_util.s; 119 } 120 REDUCE; 121 return (~sum & 0xffff); 122 } 123