1 /* $OpenBSD: in_cksum.c,v 1.2 2018/07/06 04:49:21 dlg Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 32 */ 33 34 #include <sys/types.h> 35 36 #include "interface.h" 37 38 /* 39 * Given the host-byte-order value of the checksum field in a packet 40 * header, and the network-byte-order computed checksum of the data 41 * that the checksum covers (including the checksum itself), compute 42 * what the checksum field *should* have been. 43 */ 44 u_int16_t 45 in_cksum_shouldbe(u_int16_t sum, u_int16_t computed_sum) 46 { 47 u_int32_t shouldbe; 48 49 /* 50 * The value that should have gone into the checksum field 51 * is the negative of the value gotten by summing up everything 52 * *but* the checksum field. 53 * 54 * We can compute that by subtracting the value of the checksum 55 * field from the sum of all the data in the packet, and then 56 * computing the negative of that value. 57 * 58 * "sum" is the value of the checksum field, and "computed_sum" 59 * is the negative of the sum of all the data in the packets, 60 * so that's -(-computed_sum - sum), or (sum + computed_sum). 61 * 62 * All the arithmetic in question is one's complement, so the 63 * addition must include an end-around carry; we do this by 64 * doing the arithmetic in 32 bits (with no sign-extension), 65 * and then adding the upper 16 bits of the sum, which contain 66 * the carry, to the lower 16 bits of the sum, and then do it 67 * again in case *that* sum produced a carry. 68 * 69 * As RFC 1071 notes, the checksum can be computed without 70 * byte-swapping the 16-bit words; summing 16-bit words 71 * on a big-endian machine gives a big-endian checksum, which 72 * can be directly stuffed into the big-endian checksum fields 73 * in protocol headers, and summing words on a little-endian 74 * machine gives a little-endian checksum, which must be 75 * byte-swapped before being stuffed into a big-endian checksum 76 * field. 77 * 78 * "computed_sum" is a network-byte-order value, so we must put 79 * it in host byte order before subtracting it from the 80 * host-byte-order value from the header; the adjusted checksum 81 * will be in host byte order, which is what we'll return. 82 */ 83 shouldbe = sum; 84 shouldbe += ntohs(computed_sum); 85 shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); 86 shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); 87 return shouldbe; 88 } 89 90 uint32_t 91 in_cksum_add(const void *buf, size_t len, uint32_t sum) 92 { 93 const uint16_t *words = buf; 94 95 while (len > 1) { 96 sum += *words++; 97 len -= sizeof(*words); 98 } 99 100 if (len == 1) { 101 uint8_t byte = *(const uint8_t *)words; 102 sum += htons(byte << 8); 103 } 104 105 return (sum); 106 } 107 108 uint16_t 109 in_cksum_fini(uint32_t sum) 110 { 111 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 112 sum += (sum >> 16); /* add carry */ 113 114 return (~sum); 115 } 116 117 /* 118 * compute an IP header checksum. 119 * don't modifiy the packet. 120 */ 121 uint16_t 122 in_cksum(const void *addr, size_t len, uint32_t sum) 123 { 124 return (in_cksum_fini(in_cksum_add(addr, len, sum))); 125 } 126