/*- * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * %sccs.include.redist.c% * * from tahoe: in_cksum.c 1.2 86/01/05 * @(#)in_cksum.c 1.3 (Berkeley) 01/19/91 */ #include "param.h" #include "sys/mbuf.h" #include "netinet/in.h" #include "netinet/in_systm.h" /* * Checksum routine for Internet Protocol family headers. * * This routine is very heavily used in the network * code and should be modified for each CPU to be as fast as possible. * * This implementation is 386 version. */ #undef ADDCARRY #define ADDCARRY(sum) { \ if (sum & 0xffff0000) { \ sum &= 0xffff; \ sum++; \ } \ } in_cksum(m, len) register struct mbuf *m; register int len; { union word { char c[2]; u_short s; } u; register u_short *w; register int sum = 0; register int mlen = 0; for (;m && len; m = m->m_next) { if (m->m_len == 0) continue; w = mtod(m, u_short *); if (mlen == -1) { /* * The first byte of this mbuf is the continuation * of a word spanning between this mbuf and the * last mbuf. */ /* u.c[0] is already saved when scanning previous * mbuf. */ u.c[1] = *(u_char *)w; sum += u.s; ADDCARRY(sum); w = (u_short *)((char *)w + 1); mlen = m->m_len - 1; len--; } else mlen = m->m_len; if (len < mlen) mlen = len; len -= mlen; /* * add by words. */ while ((mlen -= 2) >= 0) { if ((int)w & 0x1) { /* word is not aligned */ u.c[0] = *(char *)w; u.c[1] = *((char *)w+1); sum += u.s; w++; } else sum += *w++; ADDCARRY(sum); } if (mlen == -1) /* * This mbuf has odd number of bytes. * There could be a word split betwen * this mbuf and the next mbuf. * Save the last byte (to prepend to next mbuf). */ u.c[0] = *(u_char *)w; } if (len) printf("cksum: out of data\n"); if (mlen == -1) { /* The last mbuf has odd # of bytes. Follow the standard (the odd byte is shifted left by 8 bits) */ u.c[1] = 0; sum += u.s; ADDCARRY(sum); } return (~sum & 0xffff); }