1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2001 Charles Mott <cm@linktel.net> 5 * 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 33 /* 34 Alias_util.c contains general utilities used by other functions 35 in the packet aliasing module. At the moment, there are functions 36 for computing IP header and TCP packet checksums. 37 38 The checksum routines are based upon example code in a Unix networking 39 text written by Stevens (sorry, I can't remember the title -- but 40 at least this is a good author). 41 42 Initial Version: August, 1996 (cjm) 43 44 Version 1.7: January 9, 1997 45 Added differential checksum update function. 46 */ 47 48 #ifdef _KERNEL 49 #include <sys/param.h> 50 #include <sys/proc.h> 51 #else 52 #include <sys/types.h> 53 #include <stdio.h> 54 #endif 55 56 #include <netinet/in_systm.h> 57 #include <netinet/in.h> 58 #include <netinet/ip.h> 59 #include <netinet/tcp.h> 60 61 #ifdef _KERNEL 62 #include <netinet/libalias/alias.h> 63 #include <netinet/libalias/alias_local.h> 64 #else 65 #include "alias.h" 66 #include "alias_local.h" 67 #endif 68 69 /* 70 * Note: the checksum routines assume that the actual checksum word has 71 * been zeroed out. If the checksum word is filled with the proper value, 72 * then these routines will give a result of zero (useful for testing 73 * purposes); 74 */ 75 u_short 76 LibAliasInternetChecksum(struct libalias *la __unused, u_short * ptr, 77 int nbytes) 78 { 79 int sum, oddbyte; 80 81 LIBALIAS_LOCK(la); 82 sum = 0; 83 while (nbytes > 1) { 84 sum += *ptr++; 85 nbytes -= 2; 86 } 87 if (nbytes == 1) { 88 oddbyte = 0; 89 ((u_char *) & oddbyte)[0] = *(u_char *) ptr; 90 ((u_char *) & oddbyte)[1] = 0; 91 sum += oddbyte; 92 } 93 sum = (sum >> 16) + (sum & 0xffff); 94 sum += (sum >> 16); 95 LIBALIAS_UNLOCK(la); 96 return (~sum); 97 } 98 99 #ifndef _KERNEL 100 u_short 101 IpChecksum(struct ip *pip) 102 { 103 return (LibAliasInternetChecksum(NULL, (u_short *) pip, 104 (pip->ip_hl << 2))); 105 106 } 107 108 u_short 109 TcpChecksum(struct ip *pip) 110 { 111 u_short *ptr; 112 struct tcphdr *tc; 113 int nhdr, ntcp, nbytes; 114 int sum, oddbyte; 115 116 nhdr = pip->ip_hl << 2; 117 ntcp = ntohs(pip->ip_len) - nhdr; 118 119 tc = (struct tcphdr *)ip_next(pip); 120 ptr = (u_short *) tc; 121 122 /* Add up TCP header and data */ 123 nbytes = ntcp; 124 sum = 0; 125 while (nbytes > 1) { 126 sum += *ptr++; 127 nbytes -= 2; 128 } 129 if (nbytes == 1) { 130 oddbyte = 0; 131 ((u_char *) & oddbyte)[0] = *(u_char *) ptr; 132 ((u_char *) & oddbyte)[1] = 0; 133 sum += oddbyte; 134 } 135 /* "Pseudo-header" data */ 136 ptr = (void *)&pip->ip_dst; 137 sum += *ptr++; 138 sum += *ptr; 139 ptr = (void *)&pip->ip_src; 140 sum += *ptr++; 141 sum += *ptr; 142 sum += htons((u_short) ntcp); 143 sum += htons((u_short) pip->ip_p); 144 145 /* Roll over carry bits */ 146 sum = (sum >> 16) + (sum & 0xffff); 147 sum += (sum >> 16); 148 149 /* Return checksum */ 150 return ((u_short) ~ sum); 151 } 152 #endif /* not _KERNEL */ 153 154 void 155 DifferentialChecksum(u_short * cksum, void *newp, void *oldp, int n) 156 { 157 int i; 158 int accumulate; 159 u_short *new = newp; 160 u_short *old = oldp; 161 162 accumulate = *cksum; 163 for (i = 0; i < n; i++) { 164 accumulate -= *new++; 165 accumulate += *old++; 166 } 167 168 if (accumulate < 0) { 169 accumulate = -accumulate; 170 accumulate = (accumulate >> 16) + (accumulate & 0xffff); 171 accumulate += accumulate >> 16; 172 *cksum = (u_short) ~ accumulate; 173 } else { 174 accumulate = (accumulate >> 16) + (accumulate & 0xffff); 175 accumulate += accumulate >> 16; 176 *cksum = (u_short) accumulate; 177 } 178 } 179