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.4 (Berkeley) 10/11/92 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 #include <netinet/in.h> 20 #include <netinet/in_systm.h> 21 22 extern int oc_cksum(); 23 24 /* 25 * Checksum routine for the Internet Protocol family. 26 * 27 * This isn't as bad as it looks. For ip headers the "while" isn't 28 * executed and we just drop through to the return statement at the 29 * end. For the usual tcp or udp packet (a single header mbuf 30 * chained onto a cluster of data, we make exactly one trip through 31 * the while (for the header mbuf) and never do the hairy code 32 * inside the "if". If fact, if m_copydata & sb_compact are doing 33 * their job, we should never do the hairy code inside the "if". 34 */ 35 in_cksum(m, len) 36 register struct mbuf *m; 37 register int len; 38 { 39 register int sum = 0; 40 register int i; 41 42 while (len > m->m_len) { 43 sum = oc_cksum(mtod(m, u_char *), i = m->m_len, sum); 44 m = m->m_next; 45 len -= i; 46 if (i & 1) { 47 /* 48 * ouch - we ended on an odd byte with more 49 * to do. This xfer is obviously not interested 50 * in performance so finish things slowly. 51 */ 52 register u_char *cp; 53 54 while (len > m->m_len) { 55 cp = mtod(m, u_char *); 56 if (i & 1) { 57 i = m->m_len - 1; 58 --len; 59 sum += *cp++; 60 } else 61 i = m->m_len; 62 63 sum = oc_cksum(cp, i, sum); 64 m = m->m_next; 65 len -= i; 66 } 67 if (i & 1) { 68 cp = mtod(m, u_char *); 69 sum += *cp++; 70 return (0xffff & ~oc_cksum(cp, len - 1, sum)); 71 } 72 } 73 } 74 return (0xffff & ~oc_cksum(mtod(m, u_char *), len, sum)); 75 } 76