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