1 /* 2 * Copyright (c) 1988, 1990 Regents of the University of California. 3 * 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 7.5 (Berkeley) 06/03/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 */ 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