alias_util.c revision 173874
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 2001 Charles Mott <cm@linktel.net>
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes *
141590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241590Srgrimes * SUCH DAMAGE.
251590Srgrimes */
261590Srgrimes
271590Srgrimes#include <sys/cdefs.h>
281590Srgrimes__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_util.c 173874 2007-11-23 23:56:03Z jb $");
291590Srgrimes
301590Srgrimes
311590Srgrimes/*
321590Srgrimes    Alias_util.c contains general utilities used by other functions
331590Srgrimes    in the packet aliasing module.  At the moment, there are functions
341590Srgrimes    for computing IP header and TCP packet checksums.
3527752Scharnier
361590Srgrimes    The checksum routines are based upon example code in a Unix networking
371590Srgrimes    text written by Stevens (sorry, I can't remember the title -- but
381590Srgrimes    at least this is a good author).
391590Srgrimes
401590Srgrimes    Initial Version:  August, 1996  (cjm)
4127752Scharnier
4223693Speter    Version 1.7:  January 9, 1997
4327752Scharnier	 Added differential checksum update function.
4427752Scharnier*/
4546928Smjacob
461590Srgrimes#ifdef _KERNEL
471590Srgrimes#include <sys/param.h>
481590Srgrimes#include <sys/proc.h>
491590Srgrimes#else
501590Srgrimes#include <sys/types.h>
511590Srgrimes#include <stdio.h>
521590Srgrimes#endif
531590Srgrimes
541590Srgrimes#include <netinet/in_systm.h>
5523693Speter#include <netinet/in.h>
5623693Speter#include <netinet/ip.h>
5727752Scharnier#include <netinet/tcp.h>
581590Srgrimes
5923693Speter#ifdef _KERNEL
601590Srgrimes#include <netinet/libalias/alias.h>
611590Srgrimes#include <netinet/libalias/alias_local.h>
6223693Speter#else
631590Srgrimes#include "alias.h"
647913Sjoerg#include "alias_local.h"
657913Sjoerg#endif
667913Sjoerg
677913Sjoerg/*
687929Sjoerg * Note: the checksum routines assume that the actual checksum word has
697929Sjoerg * been zeroed out.  If the checksum word is filled with the proper value,
709541Sjoerg * then these routines will give a result of zero (useful for testing
7139260Sgibbs * purposes);
727913Sjoerg */
737913Sjoergu_short
7439260SgibbsLibAliasInternetChecksum(struct libalias *la __unused, u_short * ptr,
7539260Sgibbs	int nbytes)
7639260Sgibbs{
7739260Sgibbs	int sum, oddbyte;
7839260Sgibbs
7939260Sgibbs	LIBALIAS_LOCK(la);
8039260Sgibbs	sum = 0;
811590Srgrimes	while (nbytes > 1) {
821590Srgrimes		sum += *ptr++;
831590Srgrimes		nbytes -= 2;
841590Srgrimes	}
857913Sjoerg	if (nbytes == 1) {
867913Sjoerg		oddbyte = 0;
877913Sjoerg		((u_char *) & oddbyte)[0] = *(u_char *) ptr;
881590Srgrimes		((u_char *) & oddbyte)[1] = 0;
891590Srgrimes		sum += oddbyte;
901590Srgrimes	}
919541Sjoerg	sum = (sum >> 16) + (sum & 0xffff);
929541Sjoerg	sum += (sum >> 16);
939541Sjoerg	LIBALIAS_UNLOCK(la);
949541Sjoerg	return (~sum);
959541Sjoerg}
969541Sjoerg
979541Sjoerg#ifndef	_KERNEL
981590Srgrimesu_short
991590SrgrimesIpChecksum(struct ip *pip)
1001590Srgrimes{
1011590Srgrimes	return (LibAliasInternetChecksum(NULL, (u_short *) pip,
1021590Srgrimes	    (pip->ip_hl << 2)));
1031590Srgrimes
10441913Smjacob}
10541913Smjacob
10641913Smjacobu_short
1071590SrgrimesTcpChecksum(struct ip *pip)
10841913Smjacob{
1097913Sjoerg	u_short *ptr;
11039260Sgibbs	struct tcphdr *tc;
1117913Sjoerg	int nhdr, ntcp, nbytes;
1127929Sjoerg	int sum, oddbyte;
1137913Sjoerg	void *v;
11428492Sjoerg
11542010Smjacob	nhdr = pip->ip_hl << 2;
11642010Smjacob	ntcp = ntohs(pip->ip_len) - nhdr;
11742010Smjacob
11842010Smjacob	tc = (struct tcphdr *)ip_next(pip);
11939260Sgibbs	ptr = (u_short *) tc;
12013401Sjoerg
12141913Smjacob/* Add up TCP header and data */
12241913Smjacob	nbytes = ntcp;
12341913Smjacob	sum = 0;
12441913Smjacob	while (nbytes > 1) {
12541945Smjacob		sum += *ptr++;
12646928Smjacob		nbytes -= 2;
12746928Smjacob	}
12846928Smjacob	if (nbytes == 1) {
12946928Smjacob		oddbyte = 0;
1307913Sjoerg		((u_char *) & oddbyte)[0] = *(u_char *) ptr;
1311590Srgrimes		((u_char *) & oddbyte)[1] = 0;
1321590Srgrimes		sum += oddbyte;
1331590Srgrimes	}
1341590Srgrimes/* "Pseudo-header" data */
1351590Srgrimes	v = &pip->ip_dst;
1361590Srgrimes	ptr = v;
1377913Sjoerg	sum += *ptr++;
1387913Sjoerg	sum += *ptr;
1397929Sjoerg	v = &pip->ip_src;
1407929Sjoerg	ptr = v;
14139260Sgibbs	sum += *ptr++;
14239260Sgibbs	sum += *ptr;
14339260Sgibbs	sum += htons((u_short) ntcp);
1449541Sjoerg	sum += htons((u_short) pip->ip_p);
1457913Sjoerg
1461590Srgrimes/* Roll over carry bits */
1471590Srgrimes	sum = (sum >> 16) + (sum & 0xffff);
1481590Srgrimes	sum += (sum >> 16);
1491590Srgrimes
1501590Srgrimes/* Return checksum */
1511590Srgrimes	return ((u_short) ~ sum);
1521590Srgrimes}
1531590Srgrimes#endif	/* not _KERNEL */
1541590Srgrimes
1551590Srgrimesvoid
1561590SrgrimesDifferentialChecksum(u_short * cksum, void *newp, void *oldp, int n)
1571590Srgrimes{
1581590Srgrimes	int i;
1591590Srgrimes	int accumulate;
1601590Srgrimes	u_short *new = newp;
16124360Simp	u_short *old = oldp;
1621590Srgrimes
1631590Srgrimes	accumulate = *cksum;
1641590Srgrimes	for (i = 0; i < n; i++) {
1651590Srgrimes		accumulate -= *new++;
1661590Srgrimes		accumulate += *old++;
1671590Srgrimes	}
1681590Srgrimes
1691590Srgrimes	if (accumulate < 0) {
1701590Srgrimes		accumulate = -accumulate;
1711590Srgrimes		accumulate = (accumulate >> 16) + (accumulate & 0xffff);
1721590Srgrimes		accumulate += accumulate >> 16;
1731590Srgrimes		*cksum = (u_short) ~ accumulate;
1741590Srgrimes	} else {
1751590Srgrimes		accumulate = (accumulate >> 16) + (accumulate & 0xffff);
1761590Srgrimes		accumulate += accumulate >> 16;
1771590Srgrimes		*cksum = (u_short) accumulate;
1781590Srgrimes	}
1791590Srgrimes}
18027752Scharnier