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