133840Skarels /* 2*52796Ssklower * Copyright (c) 1988, 1992 Regents of the University of California. 333840Skarels * All rights reserved. 433840Skarels * 544474Sbostic * %sccs.include.redist.c% 633840Skarels * 7*52796Ssklower * @(#)in_cksum.c 7.4 (Berkeley) 03/02/92 833840Skarels */ 933840Skarels 10*52796Ssklower #include "param.h" 11*52796Ssklower #include "mbuf.h" 1233840Skarels 1333840Skarels /* 1433840Skarels * Checksum routine for Internet Protocol family headers (Portable Version). 1533840Skarels * 1633840Skarels * This routine is very heavily used in the network 1733840Skarels * code and should be modified for each CPU to be as fast as possible. 1833840Skarels */ 1933840Skarels 2033840Skarels #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) 2133840Skarels #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} 2233840Skarels 23*52796Ssklower in_cksum(m, len) 2433840Skarels register struct mbuf *m; 2533840Skarels register int len; 2633840Skarels { 2733840Skarels register u_short *w; 2833840Skarels register int sum = 0; 2933840Skarels register int mlen = 0; 3033840Skarels int byte_swapped = 0; 3133840Skarels 3233840Skarels union { 3333840Skarels char c[2]; 3433840Skarels u_short s; 3533840Skarels } s_util; 3633840Skarels union { 3733840Skarels u_short s[2]; 3833840Skarels long l; 3933840Skarels } l_util; 4033840Skarels 4133840Skarels for (;m && len; m = m->m_next) { 4233840Skarels if (m->m_len == 0) 4333840Skarels continue; 4433840Skarels w = mtod(m, u_short *); 4533840Skarels if (mlen == -1) { 4633840Skarels /* 4733840Skarels * The first byte of this mbuf is the continuation 4833840Skarels * of a word spanning between this mbuf and the 4933840Skarels * last mbuf. 5033840Skarels * 5133840Skarels * s_util.c[0] is already saved when scanning previous 5233840Skarels * mbuf. 5333840Skarels */ 5433840Skarels s_util.c[1] = *(char *)w; 5533840Skarels sum += s_util.s; 5633840Skarels w = (u_short *)((char *)w + 1); 5733840Skarels mlen = m->m_len - 1; 5833840Skarels len--; 5933840Skarels } else 6033840Skarels mlen = m->m_len; 6133840Skarels if (len < mlen) 6233840Skarels mlen = len; 6333840Skarels len -= mlen; 6433840Skarels /* 6533840Skarels * Force to even boundary. 6633840Skarels */ 6733840Skarels if ((1 & (int) w) && (mlen > 0)) { 6833840Skarels REDUCE; 6933840Skarels sum <<= 8; 7033840Skarels s_util.c[0] = *(u_char *)w; 7133840Skarels w = (u_short *)((char *)w + 1); 7233840Skarels mlen--; 7333840Skarels byte_swapped = 1; 7433840Skarels } 7533840Skarels /* 7633840Skarels * Unroll the loop to make overhead from 7733840Skarels * branches &c small. 7833840Skarels */ 7933840Skarels while ((mlen -= 32) >= 0) { 8033840Skarels sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 8133840Skarels sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 8233840Skarels sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 8333840Skarels sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 8433840Skarels w += 16; 8533840Skarels } 8633840Skarels mlen += 32; 8733840Skarels while ((mlen -= 8) >= 0) { 8833840Skarels sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 8933840Skarels w += 4; 9033840Skarels } 9133840Skarels mlen += 8; 9233840Skarels if (mlen == 0 && byte_swapped == 0) 9333840Skarels continue; 9433840Skarels REDUCE; 9533840Skarels while ((mlen -= 2) >= 0) { 9633840Skarels sum += *w++; 9733840Skarels } 9833840Skarels if (byte_swapped) { 9933840Skarels REDUCE; 10033840Skarels sum <<= 8; 10133840Skarels byte_swapped = 0; 10233840Skarels if (mlen == -1) { 10333840Skarels s_util.c[1] = *(char *)w; 10433840Skarels sum += s_util.s; 10533840Skarels mlen = 0; 10633840Skarels } else 10733840Skarels mlen = -1; 10833840Skarels } else if (mlen == -1) 10933840Skarels s_util.c[0] = *(char *)w; 11033840Skarels } 11133840Skarels if (len) 11233840Skarels printf("cksum: out of data\n"); 11333840Skarels if (mlen == -1) { 11433840Skarels /* The last mbuf has odd # of bytes. Follow the 11533840Skarels standard (the odd byte may be shifted left by 8 bits 11633840Skarels or not as determined by endian-ness of the machine) */ 11733840Skarels s_util.c[1] = 0; 11833840Skarels sum += s_util.s; 11933840Skarels } 12033840Skarels REDUCE; 12133840Skarels return (~sum & 0xffff); 12233840Skarels } 123