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