alias_util.c revision 124621
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: head/sys/netinet/libalias/alias_util.c 124621 2004-01-17 10:52:21Z phk $");
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
4326026Sbrian         Added differential checksum update function.
4426026Sbrian*/
4526026Sbrian
4626026Sbrian/*
4726026SbrianNote: the checksum routines assume that the actual checksum word has
4859031Srubeen zeroed out.  If the checksum word is filled with the proper value,
4926026Sbrianthen these routines will give a result of zero (useful for testing
5026026Sbrianpurposes);
5126026Sbrian*/
5299207Sbrian
53124621Sphk#include <stdio.h>
5426026Sbrian#include <sys/types.h>
5526026Sbrian#include <netinet/in_systm.h>
5626026Sbrian#include <netinet/in.h>
5726026Sbrian#include <netinet/ip.h>
5826026Sbrian#include <netinet/tcp.h>
5926026Sbrian
6027864Sbrian#include "alias.h"
6126026Sbrian#include "alias_local.h"
6226026Sbrian
6326026Sbrianu_short
64124621SphkLibAliasInternetChecksum(struct libalias *la, u_short *ptr, int nbytes)
6526026Sbrian{
6626026Sbrian    int sum, oddbyte;
6726026Sbrian
6826026Sbrian    sum = 0;
6926026Sbrian    while (nbytes > 1)
7026026Sbrian    {
7126026Sbrian        sum += *ptr++;
7226026Sbrian        nbytes -= 2;
7326026Sbrian    }
7426026Sbrian    if (nbytes == 1)
7526026Sbrian    {
7626026Sbrian        oddbyte = 0;
7745926Sluoqi        ((u_char *) &oddbyte)[0] = *(u_char *) ptr;
7845926Sluoqi        ((u_char *) &oddbyte)[1] = 0;
7926026Sbrian        sum += oddbyte;
8026026Sbrian    }
8126026Sbrian    sum = (sum >> 16) + (sum & 0xffff);
8226026Sbrian    sum += (sum >> 16);
8326026Sbrian    return(~sum);
8426026Sbrian}
8526026Sbrian
8626026Sbrianu_short
8726026SbrianIpChecksum(struct ip *pip)
8826026Sbrian{
8927864Sbrian    return( PacketAliasInternetChecksum((u_short *) pip,
9027864Sbrian            (pip->ip_hl << 2)) );
9126026Sbrian
9226026Sbrian}
9326026Sbrian
9499207Sbrianu_short
9526026SbrianTcpChecksum(struct ip *pip)
9626026Sbrian{
9726026Sbrian    u_short *ptr;
9826026Sbrian    struct tcphdr *tc;
9926026Sbrian    int nhdr, ntcp, nbytes;
10026026Sbrian    int sum, oddbyte;
10126026Sbrian
10226026Sbrian    nhdr = pip->ip_hl << 2;
10326026Sbrian    ntcp = ntohs(pip->ip_len) - nhdr;
10426026Sbrian
10526026Sbrian    tc = (struct tcphdr *) ((char *) pip + nhdr);
10626026Sbrian    ptr = (u_short *) tc;
10799207Sbrian
10826026Sbrian/* Add up TCP header and data */
10926026Sbrian    nbytes = ntcp;
11026026Sbrian    sum = 0;
11126026Sbrian    while (nbytes > 1)
11226026Sbrian    {
11326026Sbrian        sum += *ptr++;
11426026Sbrian        nbytes -= 2;
11526026Sbrian    }
11626026Sbrian    if (nbytes == 1)
11726026Sbrian    {
11826026Sbrian        oddbyte = 0;
11945926Sluoqi        ((u_char *) &oddbyte)[0] = *(u_char *) ptr;
12045926Sluoqi        ((u_char *) &oddbyte)[1] = 0;
12126026Sbrian        sum += oddbyte;
12226026Sbrian    }
12326026Sbrian
12426026Sbrian/* "Pseudo-header" data */
12526026Sbrian    ptr = (u_short *) &(pip->ip_dst);
12626026Sbrian    sum += *ptr++;
12726026Sbrian    sum += *ptr;
12826026Sbrian    ptr = (u_short *) &(pip->ip_src);
12926026Sbrian    sum += *ptr++;
13026026Sbrian    sum += *ptr;
13126026Sbrian    sum += htons((u_short) ntcp);
13226026Sbrian    sum += htons((u_short) pip->ip_p);
13326026Sbrian
13426026Sbrian/* Roll over carry bits */
13526026Sbrian    sum = (sum >> 16) + (sum & 0xffff);
13626026Sbrian    sum += (sum >> 16);
13726026Sbrian
13826026Sbrian/* Return checksum */
13926026Sbrian    return((u_short) ~sum);
14026026Sbrian}
14126026Sbrian
14226026Sbrian
14326026Sbrianvoid
14426026SbrianDifferentialChecksum(u_short *cksum, u_short *new, u_short *old, int n)
14526026Sbrian{
14626026Sbrian    int i;
14726026Sbrian    int accumulate;
14826026Sbrian
14926026Sbrian    accumulate = *cksum;
15026026Sbrian    for (i=0; i<n; i++)
15126026Sbrian    {
15226026Sbrian        accumulate -= *new++;
15326026Sbrian        accumulate += *old++;
15426026Sbrian    }
15526026Sbrian
15626026Sbrian    if (accumulate < 0)
15726026Sbrian    {
15826026Sbrian        accumulate = -accumulate;
15926026Sbrian        accumulate = (accumulate >> 16) + (accumulate & 0xffff);
16026026Sbrian        accumulate += accumulate >> 16;
16126026Sbrian        *cksum = (u_short) ~accumulate;
16226026Sbrian    }
16326026Sbrian    else
16426026Sbrian    {
16526026Sbrian        accumulate = (accumulate >> 16) + (accumulate & 0xffff);
16626026Sbrian        accumulate += accumulate >> 16;
16726026Sbrian        *cksum = (u_short) accumulate;
16826026Sbrian    }
16926026Sbrian}
17026026Sbrian
171