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