19546e36dSchristos /* in_cksum.c 29546e36dSchristos * 4.4-Lite-2 Internet checksum routine, modified to take a vector of 39546e36dSchristos * pointers/lengths giving the pieces to be checksummed. Also using 49546e36dSchristos * Tahoe/CGI version of ADDCARRY(x) macro instead of from portable version. 59546e36dSchristos */ 69546e36dSchristos 79546e36dSchristos /* 89546e36dSchristos * Copyright (c) 1988, 1992, 1993 99546e36dSchristos * The Regents of the University of California. All rights reserved. 109546e36dSchristos * 119546e36dSchristos * Redistribution and use in source and binary forms, with or without 129546e36dSchristos * modification, are permitted provided that the following conditions 139546e36dSchristos * are met: 149546e36dSchristos * 1. Redistributions of source code must retain the above copyright 159546e36dSchristos * notice, this list of conditions and the following disclaimer. 169546e36dSchristos * 2. Redistributions in binary form must reproduce the above copyright 179546e36dSchristos * notice, this list of conditions and the following disclaimer in the 189546e36dSchristos * documentation and/or other materials provided with the distribution. 199546e36dSchristos * 3. Neither the name of the University nor the names of its contributors 209546e36dSchristos * may be used to endorse or promote products derived from this software 219546e36dSchristos * without specific prior written permission. 229546e36dSchristos * 239546e36dSchristos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 249546e36dSchristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 259546e36dSchristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 269546e36dSchristos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 279546e36dSchristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 289546e36dSchristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 299546e36dSchristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 309546e36dSchristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 319546e36dSchristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 329546e36dSchristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 339546e36dSchristos * SUCH DAMAGE. 349546e36dSchristos * 359546e36dSchristos * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 369546e36dSchristos */ 379546e36dSchristos 38fdccd7e4Schristos #include <sys/cdefs.h> 39fdccd7e4Schristos #ifndef lint 40*26ba0b50Schristos __RCSID("$NetBSD: in_cksum.c,v 1.4 2024/09/02 16:15:30 christos Exp $"); 41fdccd7e4Schristos #endif 42fdccd7e4Schristos 43c74ad251Schristos # include <config.h> 449546e36dSchristos 45c74ad251Schristos #include "netdissect-stdinc.h" 469546e36dSchristos 47784088dfSchristos #include "netdissect.h" 489546e36dSchristos 499546e36dSchristos /* 509546e36dSchristos * Checksum routine for Internet Protocol family headers (Portable Version). 519546e36dSchristos * 529546e36dSchristos * This routine is very heavily used in the network 539546e36dSchristos * code and should be modified for each CPU to be as fast as possible. 549546e36dSchristos */ 559546e36dSchristos 569546e36dSchristos #define ADDCARRY(x) {if ((x) > 65535) (x) -= 65535;} 579546e36dSchristos #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} 589546e36dSchristos 59c47fd378Schristos uint16_t 609546e36dSchristos in_cksum(const struct cksum_vec *vec, int veclen) 619546e36dSchristos { 62c74ad251Schristos const uint16_t *w; 63c74ad251Schristos int sum = 0; 64c74ad251Schristos int mlen = 0; 659546e36dSchristos int byte_swapped = 0; 669546e36dSchristos 679546e36dSchristos union { 68c47fd378Schristos uint8_t c[2]; 69c47fd378Schristos uint16_t s; 709546e36dSchristos } s_util; 719546e36dSchristos union { 72c47fd378Schristos uint16_t s[2]; 73c47fd378Schristos uint32_t l; 749546e36dSchristos } l_util; 759546e36dSchristos 769546e36dSchristos for (; veclen != 0; vec++, veclen--) { 779546e36dSchristos if (vec->len == 0) 789546e36dSchristos continue; 79784088dfSchristos w = (const uint16_t *)(const void *)vec->ptr; 809546e36dSchristos if (mlen == -1) { 819546e36dSchristos /* 829546e36dSchristos * The first byte of this chunk is the continuation 839546e36dSchristos * of a word spanning between this chunk and the 849546e36dSchristos * last chunk. 859546e36dSchristos * 869546e36dSchristos * s_util.c[0] is already saved when scanning previous 879546e36dSchristos * chunk. 889546e36dSchristos */ 89c47fd378Schristos s_util.c[1] = *(const uint8_t *)w; 909546e36dSchristos sum += s_util.s; 91784088dfSchristos w = (const uint16_t *)(const void *)((const uint8_t *)w + 1); 929546e36dSchristos mlen = vec->len - 1; 939546e36dSchristos } else 949546e36dSchristos mlen = vec->len; 959546e36dSchristos /* 969546e36dSchristos * Force to even boundary. 979546e36dSchristos */ 98784088dfSchristos if ((1 & (uintptr_t) w) && (mlen > 0)) { 999546e36dSchristos REDUCE; 1009546e36dSchristos sum <<= 8; 101c47fd378Schristos s_util.c[0] = *(const uint8_t *)w; 102784088dfSchristos w = (const uint16_t *)(const void *)((const uint8_t *)w + 1); 1039546e36dSchristos mlen--; 1049546e36dSchristos byte_swapped = 1; 1059546e36dSchristos } 1069546e36dSchristos /* 1079546e36dSchristos * Unroll the loop to make overhead from 1089546e36dSchristos * branches &c small. 1099546e36dSchristos */ 1109546e36dSchristos while ((mlen -= 32) >= 0) { 1119546e36dSchristos sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 1129546e36dSchristos sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 1139546e36dSchristos sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 1149546e36dSchristos sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 1159546e36dSchristos w += 16; 1169546e36dSchristos } 1179546e36dSchristos mlen += 32; 1189546e36dSchristos while ((mlen -= 8) >= 0) { 1199546e36dSchristos sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 1209546e36dSchristos w += 4; 1219546e36dSchristos } 1229546e36dSchristos mlen += 8; 1239546e36dSchristos if (mlen == 0 && byte_swapped == 0) 1249546e36dSchristos continue; 1259546e36dSchristos REDUCE; 1269546e36dSchristos while ((mlen -= 2) >= 0) { 1279546e36dSchristos sum += *w++; 1289546e36dSchristos } 1299546e36dSchristos if (byte_swapped) { 1309546e36dSchristos REDUCE; 1319546e36dSchristos sum <<= 8; 1329546e36dSchristos byte_swapped = 0; 1339546e36dSchristos if (mlen == -1) { 134c47fd378Schristos s_util.c[1] = *(const uint8_t *)w; 1359546e36dSchristos sum += s_util.s; 1369546e36dSchristos mlen = 0; 1379546e36dSchristos } else 1389546e36dSchristos mlen = -1; 1399546e36dSchristos } else if (mlen == -1) 140c47fd378Schristos s_util.c[0] = *(const uint8_t *)w; 1419546e36dSchristos } 1429546e36dSchristos if (mlen == -1) { 1439546e36dSchristos /* The last mbuf has odd # of bytes. Follow the 1449546e36dSchristos standard (the odd byte may be shifted left by 8 bits 1459546e36dSchristos or not as determined by endian-ness of the machine) */ 1469546e36dSchristos s_util.c[1] = 0; 1479546e36dSchristos sum += s_util.s; 1489546e36dSchristos } 1499546e36dSchristos REDUCE; 1509546e36dSchristos return (~sum & 0xffff); 1519546e36dSchristos } 1529546e36dSchristos 1539546e36dSchristos /* 1549546e36dSchristos * Given the host-byte-order value of the checksum field in a packet 1559546e36dSchristos * header, and the network-byte-order computed checksum of the data 1569546e36dSchristos * that the checksum covers (including the checksum itself), compute 1579546e36dSchristos * what the checksum field *should* have been. 1589546e36dSchristos */ 159c47fd378Schristos uint16_t 160c47fd378Schristos in_cksum_shouldbe(uint16_t sum, uint16_t computed_sum) 1619546e36dSchristos { 162c47fd378Schristos uint32_t shouldbe; 1639546e36dSchristos 1649546e36dSchristos /* 1659546e36dSchristos * The value that should have gone into the checksum field 1669546e36dSchristos * is the negative of the value gotten by summing up everything 1679546e36dSchristos * *but* the checksum field. 1689546e36dSchristos * 1699546e36dSchristos * We can compute that by subtracting the value of the checksum 1709546e36dSchristos * field from the sum of all the data in the packet, and then 1719546e36dSchristos * computing the negative of that value. 1729546e36dSchristos * 1739546e36dSchristos * "sum" is the value of the checksum field, and "computed_sum" 1749546e36dSchristos * is the negative of the sum of all the data in the packets, 1759546e36dSchristos * so that's -(-computed_sum - sum), or (sum + computed_sum). 1769546e36dSchristos * 1779546e36dSchristos * All the arithmetic in question is one's complement, so the 1789546e36dSchristos * addition must include an end-around carry; we do this by 1799546e36dSchristos * doing the arithmetic in 32 bits (with no sign-extension), 1809546e36dSchristos * and then adding the upper 16 bits of the sum, which contain 1819546e36dSchristos * the carry, to the lower 16 bits of the sum, and then do it 1829546e36dSchristos * again in case *that* sum produced a carry. 1839546e36dSchristos * 1849546e36dSchristos * As RFC 1071 notes, the checksum can be computed without 1859546e36dSchristos * byte-swapping the 16-bit words; summing 16-bit words 1869546e36dSchristos * on a big-endian machine gives a big-endian checksum, which 1879546e36dSchristos * can be directly stuffed into the big-endian checksum fields 1889546e36dSchristos * in protocol headers, and summing words on a little-endian 1899546e36dSchristos * machine gives a little-endian checksum, which must be 1909546e36dSchristos * byte-swapped before being stuffed into a big-endian checksum 1919546e36dSchristos * field. 1929546e36dSchristos * 1939546e36dSchristos * "computed_sum" is a network-byte-order value, so we must put 1949546e36dSchristos * it in host byte order before subtracting it from the 1959546e36dSchristos * host-byte-order value from the header; the adjusted checksum 1969546e36dSchristos * will be in host byte order, which is what we'll return. 1979546e36dSchristos */ 1989546e36dSchristos shouldbe = sum; 1999546e36dSchristos shouldbe += ntohs(computed_sum); 2009546e36dSchristos shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); 2019546e36dSchristos shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); 202c74ad251Schristos return (uint16_t)shouldbe; 2039546e36dSchristos } 204