1 /*
2 * Copyright (c) 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * from: Utah $Hdr: in_cksum.c 1.1 90/07/09$
8 *
9 * @(#)in_cksum.c 8.1 (Berkeley) 06/10/93
10 */
11
12 /*
13 * in_cksum - checksum routine for the Internet Protocol family.
14 */
15
16 #include <sys/param.h>
17 #include <sys/mbuf.h>
18
19 extern int oc_cksum();
20
21 /*
22 * Checksum routine for the Internet Protocol family.
23 *
24 * This isn't as bad as it looks. For ip headers the "while" isn't
25 * executed and we just drop through to the return statement at the
26 * end. For the usual tcp or udp packet (a single header mbuf
27 * chained onto a cluster of data, we make exactly one trip through
28 * the while (for the header mbuf) and never do the hairy code
29 * inside the "if". If fact, if m_copydata & sb_compact are doing
30 * their job, we should never do the hairy code inside the "if".
31 */
in_cksum(m,len)32 in_cksum(m, len)
33 register struct mbuf *m;
34 register int len;
35 {
36 register int sum = 0;
37 register int i;
38
39 while (len > m->m_len) {
40 sum = oc_cksum(mtod(m, u_char *), i = m->m_len, sum);
41 m = m->m_next;
42 len -= i;
43 if (i & 1) {
44 /*
45 * ouch - we ended on an odd byte with more
46 * to do. This xfer is obviously not interested
47 * in performance so finish things slowly.
48 */
49 register u_char *cp;
50
51 while (len > m->m_len) {
52 cp = mtod(m, u_char *);
53 if (i & 1) {
54 i = m->m_len - 1;
55 --len;
56 sum += *cp++;
57 } else
58 i = m->m_len;
59
60 sum = oc_cksum(cp, i, sum);
61 m = m->m_next;
62 len -= i;
63 }
64 if (i & 1) {
65 cp = mtod(m, u_char *);
66 sum += *cp++;
67 return (0xffff & ~oc_cksum(cp, len - 1, sum));
68 }
69 }
70 }
71 return (0xffff & ~oc_cksum(mtod(m, u_char *), len, sum));
72 }
73