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