177701Sbrian/*- 285964Sbrian * Copyright (c) 2001 Charles Mott <cm@linktel.net> 377701Sbrian * All rights reserved. 477701Sbrian * 577701Sbrian * Redistribution and use in source and binary forms, with or without 677701Sbrian * modification, are permitted provided that the following conditions 777701Sbrian * are met: 877701Sbrian * 1. Redistributions of source code must retain the above copyright 977701Sbrian * notice, this list of conditions and the following disclaimer. 1077701Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1177701Sbrian * notice, this list of conditions and the following disclaimer in the 1277701Sbrian * documentation and/or other materials provided with the distribution. 1377701Sbrian * 1477701Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1577701Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1677701Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1777701Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1877701Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1977701Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2077701Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2177701Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2277701Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2377701Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2477701Sbrian * SUCH DAMAGE. 2577701Sbrian */ 2677701Sbrian 2784195Sdillon#include <sys/cdefs.h> 2884195Sdillon__FBSDID("$FreeBSD$"); 2984195Sdillon 3084195Sdillon 3126026Sbrian/* 3259031Sru Alias_util.c contains general utilities used by other functions 3326026Sbrian in the packet aliasing module. At the moment, there are functions 3426026Sbrian for computing IP header and TCP packet checksums. 3526026Sbrian 3626026Sbrian The checksum routines are based upon example code in a Unix networking 3726026Sbrian text written by Stevens (sorry, I can't remember the title -- but 3826026Sbrian at least this is a good author). 3926026Sbrian 4026026Sbrian Initial Version: August, 1996 (cjm) 4126026Sbrian 4226026Sbrian Version 1.7: January 9, 1997 43131612Sdes Added differential checksum update function. 4426026Sbrian*/ 4526026Sbrian 46145921Sglebius#ifdef _KERNEL 47145921Sglebius#include <sys/param.h> 48162674Spiso#include <sys/proc.h> 49145921Sglebius#else 50145921Sglebius#include <sys/types.h> 51124621Sphk#include <stdio.h> 52145921Sglebius#endif 53145921Sglebius 5426026Sbrian#include <netinet/in_systm.h> 5526026Sbrian#include <netinet/in.h> 5626026Sbrian#include <netinet/ip.h> 5726026Sbrian#include <netinet/tcp.h> 5826026Sbrian 59145921Sglebius#ifdef _KERNEL 60145921Sglebius#include <netinet/libalias/alias.h> 61145921Sglebius#include <netinet/libalias/alias_local.h> 62145921Sglebius#else 6327864Sbrian#include "alias.h" 6426026Sbrian#include "alias_local.h" 65145921Sglebius#endif 6626026Sbrian 67147623Sglebius/* 68147623Sglebius * Note: the checksum routines assume that the actual checksum word has 69147623Sglebius * been zeroed out. If the checksum word is filled with the proper value, 70147623Sglebius * then these routines will give a result of zero (useful for testing 71147623Sglebius * purposes); 72147623Sglebius */ 7326026Sbrianu_short 74147501SglebiusLibAliasInternetChecksum(struct libalias *la __unused, u_short * ptr, 75147501Sglebius int nbytes) 7626026Sbrian{ 77127094Sdes int sum, oddbyte; 7826026Sbrian 79165243Spiso LIBALIAS_LOCK(la); 80127094Sdes sum = 0; 81127094Sdes while (nbytes > 1) { 82127094Sdes sum += *ptr++; 83127094Sdes nbytes -= 2; 84127094Sdes } 85127094Sdes if (nbytes == 1) { 86127094Sdes oddbyte = 0; 87127094Sdes ((u_char *) & oddbyte)[0] = *(u_char *) ptr; 88127094Sdes ((u_char *) & oddbyte)[1] = 0; 89127094Sdes sum += oddbyte; 90127094Sdes } 91127094Sdes sum = (sum >> 16) + (sum & 0xffff); 92127094Sdes sum += (sum >> 16); 93165243Spiso LIBALIAS_UNLOCK(la); 94127094Sdes return (~sum); 9526026Sbrian} 9626026Sbrian 97147623Sglebius#ifndef _KERNEL 9826026Sbrianu_short 9926026SbrianIpChecksum(struct ip *pip) 10026026Sbrian{ 101147501Sglebius return (LibAliasInternetChecksum(NULL, (u_short *) pip, 102127094Sdes (pip->ip_hl << 2))); 10326026Sbrian 10426026Sbrian} 10526026Sbrian 10699207Sbrianu_short 10726026SbrianTcpChecksum(struct ip *pip) 10826026Sbrian{ 109127094Sdes u_short *ptr; 110127094Sdes struct tcphdr *tc; 111127094Sdes int nhdr, ntcp, nbytes; 112127094Sdes int sum, oddbyte; 11326026Sbrian 114127094Sdes nhdr = pip->ip_hl << 2; 115127094Sdes ntcp = ntohs(pip->ip_len) - nhdr; 11626026Sbrian 117131699Sdes tc = (struct tcphdr *)ip_next(pip); 118127094Sdes ptr = (u_short *) tc; 11999207Sbrian 12026026Sbrian/* Add up TCP header and data */ 121127094Sdes nbytes = ntcp; 122127094Sdes sum = 0; 123127094Sdes while (nbytes > 1) { 124127094Sdes sum += *ptr++; 125127094Sdes nbytes -= 2; 126127094Sdes } 127127094Sdes if (nbytes == 1) { 128127094Sdes oddbyte = 0; 129127094Sdes ((u_char *) & oddbyte)[0] = *(u_char *) ptr; 130127094Sdes ((u_char *) & oddbyte)[1] = 0; 131127094Sdes sum += oddbyte; 132127094Sdes } 13326026Sbrian/* "Pseudo-header" data */ 134174348Sdes ptr = (void *)&pip->ip_dst; 135127094Sdes sum += *ptr++; 136127094Sdes sum += *ptr; 137174348Sdes ptr = (void *)&pip->ip_src; 138127094Sdes sum += *ptr++; 139127094Sdes sum += *ptr; 140127094Sdes sum += htons((u_short) ntcp); 141127094Sdes sum += htons((u_short) pip->ip_p); 14226026Sbrian 14326026Sbrian/* Roll over carry bits */ 144127094Sdes sum = (sum >> 16) + (sum & 0xffff); 145127094Sdes sum += (sum >> 16); 14626026Sbrian 14726026Sbrian/* Return checksum */ 148127094Sdes return ((u_short) ~ sum); 14926026Sbrian} 150147623Sglebius#endif /* not _KERNEL */ 15126026Sbrian 15226026Sbrianvoid 153127689SdesDifferentialChecksum(u_short * cksum, void *newp, void *oldp, int n) 15426026Sbrian{ 155127094Sdes int i; 156127094Sdes int accumulate; 157127689Sdes u_short *new = newp; 158127689Sdes u_short *old = oldp; 15926026Sbrian 160127094Sdes accumulate = *cksum; 161127094Sdes for (i = 0; i < n; i++) { 162127094Sdes accumulate -= *new++; 163127094Sdes accumulate += *old++; 164127094Sdes } 16526026Sbrian 166127094Sdes if (accumulate < 0) { 167127094Sdes accumulate = -accumulate; 168127094Sdes accumulate = (accumulate >> 16) + (accumulate & 0xffff); 169127094Sdes accumulate += accumulate >> 16; 170127094Sdes *cksum = (u_short) ~ accumulate; 171127094Sdes } else { 172127094Sdes accumulate = (accumulate >> 16) + (accumulate & 0xffff); 173127094Sdes accumulate += accumulate >> 16; 174127094Sdes *cksum = (u_short) accumulate; 175127094Sdes } 17626026Sbrian} 177