1a9643ea8Slogwang /*-
2*22ce4affSfengbojiang * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*22ce4affSfengbojiang *
4a9643ea8Slogwang * Copyright (c) 2001 Charles Mott <[email protected]>
5a9643ea8Slogwang * All rights reserved.
6a9643ea8Slogwang *
7a9643ea8Slogwang * Redistribution and use in source and binary forms, with or without
8a9643ea8Slogwang * modification, are permitted provided that the following conditions
9a9643ea8Slogwang * are met:
10a9643ea8Slogwang * 1. Redistributions of source code must retain the above copyright
11a9643ea8Slogwang * notice, this list of conditions and the following disclaimer.
12a9643ea8Slogwang * 2. Redistributions in binary form must reproduce the above copyright
13a9643ea8Slogwang * notice, this list of conditions and the following disclaimer in the
14a9643ea8Slogwang * documentation and/or other materials provided with the distribution.
15a9643ea8Slogwang *
16a9643ea8Slogwang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17a9643ea8Slogwang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18a9643ea8Slogwang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19a9643ea8Slogwang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20a9643ea8Slogwang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21a9643ea8Slogwang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22a9643ea8Slogwang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23a9643ea8Slogwang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24a9643ea8Slogwang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25a9643ea8Slogwang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26a9643ea8Slogwang * SUCH DAMAGE.
27a9643ea8Slogwang */
28a9643ea8Slogwang
29a9643ea8Slogwang #include <sys/cdefs.h>
30a9643ea8Slogwang __FBSDID("$FreeBSD$");
31a9643ea8Slogwang
32a9643ea8Slogwang /*
33a9643ea8Slogwang Alias_util.c contains general utilities used by other functions
34a9643ea8Slogwang in the packet aliasing module. At the moment, there are functions
35a9643ea8Slogwang for computing IP header and TCP packet checksums.
36a9643ea8Slogwang
37a9643ea8Slogwang The checksum routines are based upon example code in a Unix networking
38a9643ea8Slogwang text written by Stevens (sorry, I can't remember the title -- but
39a9643ea8Slogwang at least this is a good author).
40a9643ea8Slogwang
41a9643ea8Slogwang Initial Version: August, 1996 (cjm)
42a9643ea8Slogwang
43a9643ea8Slogwang Version 1.7: January 9, 1997
44a9643ea8Slogwang Added differential checksum update function.
45a9643ea8Slogwang */
46a9643ea8Slogwang
47a9643ea8Slogwang #ifdef _KERNEL
48a9643ea8Slogwang #include <sys/param.h>
49a9643ea8Slogwang #include <sys/proc.h>
50a9643ea8Slogwang #else
51a9643ea8Slogwang #include <sys/types.h>
52a9643ea8Slogwang #include <stdio.h>
53a9643ea8Slogwang #endif
54a9643ea8Slogwang
55a9643ea8Slogwang #include <netinet/in_systm.h>
56a9643ea8Slogwang #include <netinet/in.h>
57a9643ea8Slogwang #include <netinet/ip.h>
58a9643ea8Slogwang #include <netinet/tcp.h>
59a9643ea8Slogwang
60a9643ea8Slogwang #ifdef _KERNEL
61a9643ea8Slogwang #include <netinet/libalias/alias.h>
62a9643ea8Slogwang #include <netinet/libalias/alias_local.h>
63a9643ea8Slogwang #else
64a9643ea8Slogwang #include "alias.h"
65a9643ea8Slogwang #include "alias_local.h"
66a9643ea8Slogwang #endif
67a9643ea8Slogwang
68a9643ea8Slogwang /*
69a9643ea8Slogwang * Note: the checksum routines assume that the actual checksum word has
70a9643ea8Slogwang * been zeroed out. If the checksum word is filled with the proper value,
71a9643ea8Slogwang * then these routines will give a result of zero (useful for testing
72a9643ea8Slogwang * purposes);
73a9643ea8Slogwang */
74a9643ea8Slogwang u_short
LibAliasInternetChecksum(struct libalias * la __unused,u_short * ptr,int nbytes)75a9643ea8Slogwang LibAliasInternetChecksum(struct libalias *la __unused, u_short * ptr,
76a9643ea8Slogwang int nbytes)
77a9643ea8Slogwang {
78a9643ea8Slogwang int sum, oddbyte;
79a9643ea8Slogwang
80a9643ea8Slogwang LIBALIAS_LOCK(la);
81a9643ea8Slogwang sum = 0;
82a9643ea8Slogwang while (nbytes > 1) {
83a9643ea8Slogwang sum += *ptr++;
84a9643ea8Slogwang nbytes -= 2;
85a9643ea8Slogwang }
86a9643ea8Slogwang if (nbytes == 1) {
87a9643ea8Slogwang oddbyte = 0;
88a9643ea8Slogwang ((u_char *) & oddbyte)[0] = *(u_char *) ptr;
89a9643ea8Slogwang ((u_char *) & oddbyte)[1] = 0;
90a9643ea8Slogwang sum += oddbyte;
91a9643ea8Slogwang }
92a9643ea8Slogwang sum = (sum >> 16) + (sum & 0xffff);
93a9643ea8Slogwang sum += (sum >> 16);
94a9643ea8Slogwang LIBALIAS_UNLOCK(la);
95a9643ea8Slogwang return (~sum);
96a9643ea8Slogwang }
97a9643ea8Slogwang
98a9643ea8Slogwang #ifndef _KERNEL
99a9643ea8Slogwang u_short
IpChecksum(struct ip * pip)100a9643ea8Slogwang IpChecksum(struct ip *pip)
101a9643ea8Slogwang {
102a9643ea8Slogwang return (LibAliasInternetChecksum(NULL, (u_short *) pip,
103a9643ea8Slogwang (pip->ip_hl << 2)));
104a9643ea8Slogwang
105a9643ea8Slogwang }
106a9643ea8Slogwang
107a9643ea8Slogwang u_short
TcpChecksum(struct ip * pip)108a9643ea8Slogwang TcpChecksum(struct ip *pip)
109a9643ea8Slogwang {
110a9643ea8Slogwang u_short *ptr;
111a9643ea8Slogwang struct tcphdr *tc;
112a9643ea8Slogwang int nhdr, ntcp, nbytes;
113a9643ea8Slogwang int sum, oddbyte;
114a9643ea8Slogwang
115a9643ea8Slogwang nhdr = pip->ip_hl << 2;
116a9643ea8Slogwang ntcp = ntohs(pip->ip_len) - nhdr;
117a9643ea8Slogwang
118a9643ea8Slogwang tc = (struct tcphdr *)ip_next(pip);
119a9643ea8Slogwang ptr = (u_short *) tc;
120a9643ea8Slogwang
121a9643ea8Slogwang /* Add up TCP header and data */
122a9643ea8Slogwang nbytes = ntcp;
123a9643ea8Slogwang sum = 0;
124a9643ea8Slogwang while (nbytes > 1) {
125a9643ea8Slogwang sum += *ptr++;
126a9643ea8Slogwang nbytes -= 2;
127a9643ea8Slogwang }
128a9643ea8Slogwang if (nbytes == 1) {
129a9643ea8Slogwang oddbyte = 0;
130a9643ea8Slogwang ((u_char *) & oddbyte)[0] = *(u_char *) ptr;
131a9643ea8Slogwang ((u_char *) & oddbyte)[1] = 0;
132a9643ea8Slogwang sum += oddbyte;
133a9643ea8Slogwang }
134a9643ea8Slogwang /* "Pseudo-header" data */
135a9643ea8Slogwang ptr = (void *)&pip->ip_dst;
136a9643ea8Slogwang sum += *ptr++;
137a9643ea8Slogwang sum += *ptr;
138a9643ea8Slogwang ptr = (void *)&pip->ip_src;
139a9643ea8Slogwang sum += *ptr++;
140a9643ea8Slogwang sum += *ptr;
141a9643ea8Slogwang sum += htons((u_short) ntcp);
142a9643ea8Slogwang sum += htons((u_short) pip->ip_p);
143a9643ea8Slogwang
144a9643ea8Slogwang /* Roll over carry bits */
145a9643ea8Slogwang sum = (sum >> 16) + (sum & 0xffff);
146a9643ea8Slogwang sum += (sum >> 16);
147a9643ea8Slogwang
148a9643ea8Slogwang /* Return checksum */
149a9643ea8Slogwang return ((u_short) ~ sum);
150a9643ea8Slogwang }
151a9643ea8Slogwang #endif /* not _KERNEL */
152a9643ea8Slogwang
153a9643ea8Slogwang void
DifferentialChecksum(u_short * cksum,void * newp,void * oldp,int n)154a9643ea8Slogwang DifferentialChecksum(u_short * cksum, void *newp, void *oldp, int n)
155a9643ea8Slogwang {
156a9643ea8Slogwang int i;
157a9643ea8Slogwang int accumulate;
158a9643ea8Slogwang u_short *new = newp;
159a9643ea8Slogwang u_short *old = oldp;
160a9643ea8Slogwang
161a9643ea8Slogwang accumulate = *cksum;
162a9643ea8Slogwang for (i = 0; i < n; i++) {
163a9643ea8Slogwang accumulate -= *new++;
164a9643ea8Slogwang accumulate += *old++;
165a9643ea8Slogwang }
166a9643ea8Slogwang
167a9643ea8Slogwang if (accumulate < 0) {
168a9643ea8Slogwang accumulate = -accumulate;
169a9643ea8Slogwang accumulate = (accumulate >> 16) + (accumulate & 0xffff);
170a9643ea8Slogwang accumulate += accumulate >> 16;
171a9643ea8Slogwang *cksum = (u_short) ~ accumulate;
172a9643ea8Slogwang } else {
173a9643ea8Slogwang accumulate = (accumulate >> 16) + (accumulate & 0xffff);
174a9643ea8Slogwang accumulate += accumulate >> 16;
175a9643ea8Slogwang *cksum = (u_short) accumulate;
176a9643ea8Slogwang }
177a9643ea8Slogwang }
178