xref: /freebsd/sys/netinet/libalias/alias_util.c (revision 685dc743)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 /*
31     Alias_util.c contains general utilities used by other functions
32     in the packet aliasing module.  At the moment, there are functions
33     for computing IP header and TCP packet checksums.
34 
35     The checksum routines are based upon example code in a Unix networking
36     text written by Stevens (sorry, I can't remember the title -- but
37     at least this is a good author).
38 
39     Initial Version:  August, 1996  (cjm)
40 
41     Version 1.7:  January 9, 1997
42 	 Added differential checksum update function.
43 */
44 
45 #ifdef _KERNEL
46 #include <sys/param.h>
47 #include <sys/proc.h>
48 #else
49 #include <sys/types.h>
50 #include <stdio.h>
51 #endif
52 
53 #include <netinet/in_systm.h>
54 #include <netinet/in.h>
55 #include <netinet/ip.h>
56 #include <netinet/tcp.h>
57 
58 #ifdef _KERNEL
59 #include <netinet/libalias/alias.h>
60 #include <netinet/libalias/alias_local.h>
61 #else
62 #include "alias.h"
63 #include "alias_local.h"
64 #endif
65 
66 /*
67  * Note: the checksum routines assume that the actual checksum word has
68  * been zeroed out.  If the checksum word is filled with the proper value,
69  * then these routines will give a result of zero (useful for testing
70  * purposes);
71  */
72 u_short
LibAliasInternetChecksum(struct libalias * la __unused,u_short * ptr,int nbytes)73 LibAliasInternetChecksum(struct libalias *la __unused, u_short *ptr,
74     int nbytes)
75 {
76 	int sum, oddbyte;
77 
78 	LIBALIAS_LOCK(la);
79 	sum = 0;
80 	while (nbytes > 1) {
81 		sum += *ptr++;
82 		nbytes -= 2;
83 	}
84 	if (nbytes == 1) {
85 		oddbyte = 0;
86 		((u_char *)&oddbyte)[0] = *(u_char *)ptr;
87 		((u_char *)&oddbyte)[1] = 0;
88 		sum += oddbyte;
89 	}
90 	sum = (sum >> 16) + (sum & 0xffff);
91 	sum += (sum >> 16);
92 	LIBALIAS_UNLOCK(la);
93 	return (~sum);
94 }
95 
96 #ifndef _KERNEL
97 u_short
IpChecksum(struct ip * pip)98 IpChecksum(struct ip *pip)
99 {
100 	return (LibAliasInternetChecksum(NULL, (u_short *)pip,
101 	    (pip->ip_hl << 2)));
102 
103 }
104 
105 u_short
TcpChecksum(struct ip * pip)106 TcpChecksum(struct ip *pip)
107 {
108 	u_short *ptr;
109 	struct tcphdr *tc;
110 	int nhdr, ntcp, nbytes;
111 	int sum, oddbyte;
112 
113 	nhdr = pip->ip_hl << 2;
114 	ntcp = ntohs(pip->ip_len) - nhdr;
115 
116 	tc = (struct tcphdr *)ip_next(pip);
117 	ptr = (u_short *)tc;
118 
119 /* Add up TCP header and data */
120 	nbytes = ntcp;
121 	sum = 0;
122 	while (nbytes > 1) {
123 		sum += *ptr++;
124 		nbytes -= 2;
125 	}
126 	if (nbytes == 1) {
127 		oddbyte = 0;
128 		((u_char *)&oddbyte)[0] = *(u_char *)ptr;
129 		((u_char *)&oddbyte)[1] = 0;
130 		sum += oddbyte;
131 	}
132 /* "Pseudo-header" data */
133 	ptr = (void *)&pip->ip_dst;
134 	sum += *ptr++;
135 	sum += *ptr;
136 	ptr = (void *)&pip->ip_src;
137 	sum += *ptr++;
138 	sum += *ptr;
139 	sum += htons((u_short)ntcp);
140 	sum += htons((u_short)pip->ip_p);
141 
142 /* Roll over carry bits */
143 	sum = (sum >> 16) + (sum & 0xffff);
144 	sum += (sum >> 16);
145 
146 /* Return checksum */
147 	return ((u_short)~sum);
148 }
149 #endif	/* not _KERNEL */
150 
151 void
DifferentialChecksum(u_short * cksum,void * newp,void * oldp,int n)152 DifferentialChecksum(u_short *cksum, void *newp, void *oldp, int n)
153 {
154 	int i;
155 	int accumulate;
156 	u_short *new = newp;
157 	u_short *old = oldp;
158 
159 	accumulate = *cksum;
160 	for (i = 0; i < n; i++) {
161 		accumulate -= *new++;
162 		accumulate += *old++;
163 	}
164 
165 	if (accumulate < 0) {
166 		accumulate = -accumulate;
167 		accumulate = (accumulate >> 16) + (accumulate & 0xffff);
168 		accumulate += accumulate >> 16;
169 		*cksum = (u_short)~accumulate;
170 	} else {
171 		accumulate = (accumulate >> 16) + (accumulate & 0xffff);
172 		accumulate += accumulate >> 16;
173 		*cksum = (u_short)accumulate;
174 	}
175 }
176