1f987e1bdSBrian Somers /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
4e83aaae3SBrian Somers * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5f987e1bdSBrian Somers * All rights reserved.
6f987e1bdSBrian Somers *
7f987e1bdSBrian Somers * Redistribution and use in source and binary forms, with or without
8f987e1bdSBrian Somers * modification, are permitted provided that the following conditions
9f987e1bdSBrian Somers * are met:
10f987e1bdSBrian Somers * 1. Redistributions of source code must retain the above copyright
11f987e1bdSBrian Somers * notice, this list of conditions and the following disclaimer.
12f987e1bdSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright
13f987e1bdSBrian Somers * notice, this list of conditions and the following disclaimer in the
14f987e1bdSBrian Somers * documentation and/or other materials provided with the distribution.
15f987e1bdSBrian Somers *
16f987e1bdSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f987e1bdSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f987e1bdSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f987e1bdSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f987e1bdSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f987e1bdSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f987e1bdSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f987e1bdSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f987e1bdSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f987e1bdSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f987e1bdSBrian Somers * SUCH DAMAGE.
27f987e1bdSBrian Somers */
28f987e1bdSBrian Somers
29e2505aa6SMatthew Dillon #include <sys/cdefs.h>
303b160b8bSBrian Somers /*
3191cc2995SRuslan Ermilov Alias_util.c contains general utilities used by other functions
323b160b8bSBrian Somers in the packet aliasing module. At the moment, there are functions
333b160b8bSBrian Somers for computing IP header and TCP packet checksums.
343b160b8bSBrian Somers
353b160b8bSBrian Somers The checksum routines are based upon example code in a Unix networking
363b160b8bSBrian Somers text written by Stevens (sorry, I can't remember the title -- but
373b160b8bSBrian Somers at least this is a good author).
383b160b8bSBrian Somers
393b160b8bSBrian Somers Initial Version: August, 1996 (cjm)
403b160b8bSBrian Somers
413b160b8bSBrian Somers Version 1.7: January 9, 1997
423b160b8bSBrian Somers Added differential checksum update function.
433b160b8bSBrian Somers */
443b160b8bSBrian Somers
45c649a2e0SGleb Smirnoff #ifdef _KERNEL
46c649a2e0SGleb Smirnoff #include <sys/param.h>
47be4f3cd0SPaolo Pisati #include <sys/proc.h>
48c649a2e0SGleb Smirnoff #else
493b160b8bSBrian Somers #include <sys/types.h>
50c649a2e0SGleb Smirnoff #include <stdio.h>
51c649a2e0SGleb Smirnoff #endif
52c649a2e0SGleb Smirnoff
533b160b8bSBrian Somers #include <netinet/in_systm.h>
543b160b8bSBrian Somers #include <netinet/in.h>
553b160b8bSBrian Somers #include <netinet/ip.h>
563b160b8bSBrian Somers #include <netinet/tcp.h>
573b160b8bSBrian Somers
58c649a2e0SGleb Smirnoff #ifdef _KERNEL
59c649a2e0SGleb Smirnoff #include <netinet/libalias/alias.h>
60c649a2e0SGleb Smirnoff #include <netinet/libalias/alias_local.h>
61c649a2e0SGleb Smirnoff #else
623efa11bbSBrian Somers #include "alias.h"
633b160b8bSBrian Somers #include "alias_local.h"
64c649a2e0SGleb Smirnoff #endif
653b160b8bSBrian Somers
6659dde15eSGleb Smirnoff /*
6759dde15eSGleb Smirnoff * Note: the checksum routines assume that the actual checksum word has
6859dde15eSGleb Smirnoff * been zeroed out. If the checksum word is filled with the proper value,
6959dde15eSGleb Smirnoff * then these routines will give a result of zero (useful for testing
7059dde15eSGleb Smirnoff * purposes);
7159dde15eSGleb Smirnoff */
723b160b8bSBrian Somers u_short
LibAliasInternetChecksum(struct libalias * la __unused,u_short * ptr,int nbytes)7372f2d657SGleb Smirnoff LibAliasInternetChecksum(struct libalias *la __unused, u_short *ptr,
7472f2d657SGleb Smirnoff int nbytes)
753b160b8bSBrian Somers {
763b160b8bSBrian Somers int sum, oddbyte;
773b160b8bSBrian Somers
78ccd57eeaSPaolo Pisati LIBALIAS_LOCK(la);
793b160b8bSBrian Somers sum = 0;
80f0f93429SDag-Erling Smørgrav while (nbytes > 1) {
813b160b8bSBrian Somers sum += *ptr++;
823b160b8bSBrian Somers nbytes -= 2;
833b160b8bSBrian Somers }
84f0f93429SDag-Erling Smørgrav if (nbytes == 1) {
853b160b8bSBrian Somers oddbyte = 0;
8646d28b44SLuoqi Chen ((u_char *)&oddbyte)[0] = *(u_char *)ptr;
8746d28b44SLuoqi Chen ((u_char *)&oddbyte)[1] = 0;
883b160b8bSBrian Somers sum += oddbyte;
893b160b8bSBrian Somers }
903b160b8bSBrian Somers sum = (sum >> 16) + (sum & 0xffff);
913b160b8bSBrian Somers sum += (sum >> 16);
92ccd57eeaSPaolo Pisati LIBALIAS_UNLOCK(la);
933b160b8bSBrian Somers return (~sum);
943b160b8bSBrian Somers }
953b160b8bSBrian Somers
9659dde15eSGleb Smirnoff #ifndef _KERNEL
973b160b8bSBrian Somers u_short
IpChecksum(struct ip * pip)983b160b8bSBrian Somers IpChecksum(struct ip *pip)
993b160b8bSBrian Somers {
10072f2d657SGleb Smirnoff return (LibAliasInternetChecksum(NULL, (u_short *)pip,
1013efa11bbSBrian Somers (pip->ip_hl << 2)));
1023b160b8bSBrian Somers
1033b160b8bSBrian Somers }
1043b160b8bSBrian Somers
1053b160b8bSBrian Somers u_short
TcpChecksum(struct ip * pip)1063b160b8bSBrian Somers TcpChecksum(struct ip *pip)
1073b160b8bSBrian Somers {
1083b160b8bSBrian Somers u_short *ptr;
1093b160b8bSBrian Somers struct tcphdr *tc;
1103b160b8bSBrian Somers int nhdr, ntcp, nbytes;
1113b160b8bSBrian Somers int sum, oddbyte;
1123b160b8bSBrian Somers
1133b160b8bSBrian Somers nhdr = pip->ip_hl << 2;
1143b160b8bSBrian Somers ntcp = ntohs(pip->ip_len) - nhdr;
1153b160b8bSBrian Somers
1169fa0fd26SDag-Erling Smørgrav tc = (struct tcphdr *)ip_next(pip);
1173b160b8bSBrian Somers ptr = (u_short *)tc;
1183b160b8bSBrian Somers
1193b160b8bSBrian Somers /* Add up TCP header and data */
1203b160b8bSBrian Somers nbytes = ntcp;
1213b160b8bSBrian Somers sum = 0;
122f0f93429SDag-Erling Smørgrav while (nbytes > 1) {
1233b160b8bSBrian Somers sum += *ptr++;
1243b160b8bSBrian Somers nbytes -= 2;
1253b160b8bSBrian Somers }
126f0f93429SDag-Erling Smørgrav if (nbytes == 1) {
1273b160b8bSBrian Somers oddbyte = 0;
12846d28b44SLuoqi Chen ((u_char *)&oddbyte)[0] = *(u_char *)ptr;
12946d28b44SLuoqi Chen ((u_char *)&oddbyte)[1] = 0;
1303b160b8bSBrian Somers sum += oddbyte;
1313b160b8bSBrian Somers }
1323b160b8bSBrian Somers /* "Pseudo-header" data */
1336c7faee2SDag-Erling Smørgrav ptr = (void *)&pip->ip_dst;
1343b160b8bSBrian Somers sum += *ptr++;
1353b160b8bSBrian Somers sum += *ptr;
1366c7faee2SDag-Erling Smørgrav ptr = (void *)&pip->ip_src;
1373b160b8bSBrian Somers sum += *ptr++;
1383b160b8bSBrian Somers sum += *ptr;
1393b160b8bSBrian Somers sum += htons((u_short)ntcp);
1403b160b8bSBrian Somers sum += htons((u_short)pip->ip_p);
1413b160b8bSBrian Somers
1423b160b8bSBrian Somers /* Roll over carry bits */
1433b160b8bSBrian Somers sum = (sum >> 16) + (sum & 0xffff);
1443b160b8bSBrian Somers sum += (sum >> 16);
1453b160b8bSBrian Somers
1463b160b8bSBrian Somers /* Return checksum */
1473b160b8bSBrian Somers return ((u_short)~sum);
1483b160b8bSBrian Somers }
14959dde15eSGleb Smirnoff #endif /* not _KERNEL */
1503b160b8bSBrian Somers
1513b160b8bSBrian Somers void
DifferentialChecksum(u_short * cksum,void * newp,void * oldp,int n)1522871c501SDag-Erling Smørgrav DifferentialChecksum(u_short *cksum, void *newp, void *oldp, int n)
1533b160b8bSBrian Somers {
1543b160b8bSBrian Somers int i;
1553b160b8bSBrian Somers int accumulate;
1562871c501SDag-Erling Smørgrav u_short *new = newp;
1572871c501SDag-Erling Smørgrav u_short *old = oldp;
1583b160b8bSBrian Somers
1593b160b8bSBrian Somers accumulate = *cksum;
160f0f93429SDag-Erling Smørgrav for (i = 0; i < n; i++) {
1613b160b8bSBrian Somers accumulate -= *new++;
1623b160b8bSBrian Somers accumulate += *old++;
1633b160b8bSBrian Somers }
1643b160b8bSBrian Somers
165f0f93429SDag-Erling Smørgrav if (accumulate < 0) {
1663b160b8bSBrian Somers accumulate = -accumulate;
1673b160b8bSBrian Somers accumulate = (accumulate >> 16) + (accumulate & 0xffff);
1683b160b8bSBrian Somers accumulate += accumulate >> 16;
1693b160b8bSBrian Somers *cksum = (u_short)~accumulate;
170f0f93429SDag-Erling Smørgrav } else {
1713b160b8bSBrian Somers accumulate = (accumulate >> 16) + (accumulate & 0xffff);
1723b160b8bSBrian Somers accumulate += accumulate >> 16;
1733b160b8bSBrian Somers *cksum = (u_short)accumulate;
1743b160b8bSBrian Somers }
1753b160b8bSBrian Somers }
176