1235427Sdelphij/* in_cksum.c 2235427Sdelphij * 4.4-Lite-2 Internet checksum routine, modified to take a vector of 3235427Sdelphij * pointers/lengths giving the pieces to be checksummed. Also using 4235427Sdelphij * Tahoe/CGI version of ADDCARRY(x) macro instead of from portable version. 5235427Sdelphij */ 6235427Sdelphij 7235427Sdelphij/* 8235427Sdelphij * Copyright (c) 1988, 1992, 1993 9235427Sdelphij * The Regents of the University of California. All rights reserved. 10235427Sdelphij * 11235427Sdelphij * Redistribution and use in source and binary forms, with or without 12235427Sdelphij * modification, are permitted provided that the following conditions 13235427Sdelphij * are met: 14235427Sdelphij * 1. Redistributions of source code must retain the above copyright 15235427Sdelphij * notice, this list of conditions and the following disclaimer. 16235427Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 17235427Sdelphij * notice, this list of conditions and the following disclaimer in the 18235427Sdelphij * documentation and/or other materials provided with the distribution. 19235427Sdelphij * 3. Neither the name of the University nor the names of its contributors 20235427Sdelphij * may be used to endorse or promote products derived from this software 21235427Sdelphij * without specific prior written permission. 22235427Sdelphij * 23235427Sdelphij * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24235427Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25235427Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26235427Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27235427Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28235427Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29235427Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30235427Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31235427Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32235427Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33235427Sdelphij * SUCH DAMAGE. 34235427Sdelphij * 35235427Sdelphij * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 36235427Sdelphij */ 37235427Sdelphij 38235427Sdelphij#ifdef HAVE_CONFIG_H 39235427Sdelphij# include "config.h" 40235427Sdelphij#endif 41235427Sdelphij 42313537Sglebius#include <netdissect-stdinc.h> 43235427Sdelphij 44313537Sglebius#include "netdissect.h" 45235427Sdelphij 46235427Sdelphij/* 47235427Sdelphij * Checksum routine for Internet Protocol family headers (Portable Version). 48235427Sdelphij * 49235427Sdelphij * This routine is very heavily used in the network 50235427Sdelphij * code and should be modified for each CPU to be as fast as possible. 51235427Sdelphij */ 52235427Sdelphij 53235427Sdelphij#define ADDCARRY(x) {if ((x) > 65535) (x) -= 65535;} 54235427Sdelphij#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} 55235427Sdelphij 56276788Sdelphijuint16_t 57235427Sdelphijin_cksum(const struct cksum_vec *vec, int veclen) 58235427Sdelphij{ 59276788Sdelphij register const uint16_t *w; 60235427Sdelphij register int sum = 0; 61235427Sdelphij register int mlen = 0; 62235427Sdelphij int byte_swapped = 0; 63235427Sdelphij 64235427Sdelphij union { 65276788Sdelphij uint8_t c[2]; 66276788Sdelphij uint16_t s; 67235427Sdelphij } s_util; 68235427Sdelphij union { 69276788Sdelphij uint16_t s[2]; 70276788Sdelphij uint32_t l; 71235427Sdelphij } l_util; 72235427Sdelphij 73235427Sdelphij for (; veclen != 0; vec++, veclen--) { 74235427Sdelphij if (vec->len == 0) 75235427Sdelphij continue; 76313537Sglebius w = (const uint16_t *)(const void *)vec->ptr; 77235427Sdelphij if (mlen == -1) { 78235427Sdelphij /* 79235427Sdelphij * The first byte of this chunk is the continuation 80235427Sdelphij * of a word spanning between this chunk and the 81235427Sdelphij * last chunk. 82235427Sdelphij * 83235427Sdelphij * s_util.c[0] is already saved when scanning previous 84235427Sdelphij * chunk. 85235427Sdelphij */ 86276788Sdelphij s_util.c[1] = *(const uint8_t *)w; 87235427Sdelphij sum += s_util.s; 88313537Sglebius w = (const uint16_t *)(const void *)((const uint8_t *)w + 1); 89235427Sdelphij mlen = vec->len - 1; 90235427Sdelphij } else 91235427Sdelphij mlen = vec->len; 92235427Sdelphij /* 93235427Sdelphij * Force to even boundary. 94235427Sdelphij */ 95313537Sglebius if ((1 & (uintptr_t) w) && (mlen > 0)) { 96235427Sdelphij REDUCE; 97235427Sdelphij sum <<= 8; 98276788Sdelphij s_util.c[0] = *(const uint8_t *)w; 99313537Sglebius w = (const uint16_t *)(const void *)((const uint8_t *)w + 1); 100235427Sdelphij mlen--; 101235427Sdelphij byte_swapped = 1; 102235427Sdelphij } 103235427Sdelphij /* 104235427Sdelphij * Unroll the loop to make overhead from 105235427Sdelphij * branches &c small. 106235427Sdelphij */ 107235427Sdelphij while ((mlen -= 32) >= 0) { 108235427Sdelphij sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 109235427Sdelphij sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 110235427Sdelphij sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 111235427Sdelphij sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 112235427Sdelphij w += 16; 113235427Sdelphij } 114235427Sdelphij mlen += 32; 115235427Sdelphij while ((mlen -= 8) >= 0) { 116235427Sdelphij sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 117235427Sdelphij w += 4; 118235427Sdelphij } 119235427Sdelphij mlen += 8; 120235427Sdelphij if (mlen == 0 && byte_swapped == 0) 121235427Sdelphij continue; 122235427Sdelphij REDUCE; 123235427Sdelphij while ((mlen -= 2) >= 0) { 124235427Sdelphij sum += *w++; 125235427Sdelphij } 126235427Sdelphij if (byte_swapped) { 127235427Sdelphij REDUCE; 128235427Sdelphij sum <<= 8; 129235427Sdelphij byte_swapped = 0; 130235427Sdelphij if (mlen == -1) { 131276788Sdelphij s_util.c[1] = *(const uint8_t *)w; 132235427Sdelphij sum += s_util.s; 133235427Sdelphij mlen = 0; 134235427Sdelphij } else 135235427Sdelphij mlen = -1; 136235427Sdelphij } else if (mlen == -1) 137276788Sdelphij s_util.c[0] = *(const uint8_t *)w; 138235427Sdelphij } 139235427Sdelphij if (mlen == -1) { 140235427Sdelphij /* The last mbuf has odd # of bytes. Follow the 141235427Sdelphij standard (the odd byte may be shifted left by 8 bits 142235427Sdelphij or not as determined by endian-ness of the machine) */ 143235427Sdelphij s_util.c[1] = 0; 144235427Sdelphij sum += s_util.s; 145235427Sdelphij } 146235427Sdelphij REDUCE; 147235427Sdelphij return (~sum & 0xffff); 148235427Sdelphij} 149235427Sdelphij 150235427Sdelphij/* 151235427Sdelphij * Given the host-byte-order value of the checksum field in a packet 152235427Sdelphij * header, and the network-byte-order computed checksum of the data 153235427Sdelphij * that the checksum covers (including the checksum itself), compute 154235427Sdelphij * what the checksum field *should* have been. 155235427Sdelphij */ 156276788Sdelphijuint16_t 157276788Sdelphijin_cksum_shouldbe(uint16_t sum, uint16_t computed_sum) 158235427Sdelphij{ 159276788Sdelphij uint32_t shouldbe; 160235427Sdelphij 161235427Sdelphij /* 162235427Sdelphij * The value that should have gone into the checksum field 163235427Sdelphij * is the negative of the value gotten by summing up everything 164235427Sdelphij * *but* the checksum field. 165235427Sdelphij * 166235427Sdelphij * We can compute that by subtracting the value of the checksum 167235427Sdelphij * field from the sum of all the data in the packet, and then 168235427Sdelphij * computing the negative of that value. 169235427Sdelphij * 170235427Sdelphij * "sum" is the value of the checksum field, and "computed_sum" 171235427Sdelphij * is the negative of the sum of all the data in the packets, 172235427Sdelphij * so that's -(-computed_sum - sum), or (sum + computed_sum). 173235427Sdelphij * 174235427Sdelphij * All the arithmetic in question is one's complement, so the 175235427Sdelphij * addition must include an end-around carry; we do this by 176235427Sdelphij * doing the arithmetic in 32 bits (with no sign-extension), 177235427Sdelphij * and then adding the upper 16 bits of the sum, which contain 178235427Sdelphij * the carry, to the lower 16 bits of the sum, and then do it 179235427Sdelphij * again in case *that* sum produced a carry. 180235427Sdelphij * 181235427Sdelphij * As RFC 1071 notes, the checksum can be computed without 182235427Sdelphij * byte-swapping the 16-bit words; summing 16-bit words 183235427Sdelphij * on a big-endian machine gives a big-endian checksum, which 184235427Sdelphij * can be directly stuffed into the big-endian checksum fields 185235427Sdelphij * in protocol headers, and summing words on a little-endian 186235427Sdelphij * machine gives a little-endian checksum, which must be 187235427Sdelphij * byte-swapped before being stuffed into a big-endian checksum 188235427Sdelphij * field. 189235427Sdelphij * 190235427Sdelphij * "computed_sum" is a network-byte-order value, so we must put 191235427Sdelphij * it in host byte order before subtracting it from the 192235427Sdelphij * host-byte-order value from the header; the adjusted checksum 193235427Sdelphij * will be in host byte order, which is what we'll return. 194235427Sdelphij */ 195235427Sdelphij shouldbe = sum; 196235427Sdelphij shouldbe += ntohs(computed_sum); 197235427Sdelphij shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); 198235427Sdelphij shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); 199235427Sdelphij return shouldbe; 200235427Sdelphij} 201