1 /* $NetBSD: ipcomp_core.c,v 1.20 2002/11/02 07:30:59 perry Exp $ */
2 /* $KAME: ipcomp_core.c,v 1.25 2001/07/26 06:53:17 jinmei Exp $ */
3
4 /*
5 * Copyright (C) 1999 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * RFC2393 IP payload compression protocol (IPComp).
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ipcomp_core.c,v 1.20 2002/11/02 07:30:59 perry Exp $");
39
40 #include "opt_inet.h"
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/domain.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/errno.h>
50 #include <sys/time.h>
51 #include <sys/kernel.h>
52 #include <sys/syslog.h>
53 #include <sys/queue.h>
54
55 #include <net/if.h>
56 #include <net/route.h>
57 #include <net/netisr.h>
58 #include <net/zlib.h>
59 #include <machine/cpu.h>
60
61 #include <netinet6/ipcomp.h>
62 #include <netinet6/ipsec.h>
63
64 #include <machine/stdarg.h>
65
66 #include <net/net_osdep.h>
67
68 static void *deflate_alloc __P((void *, u_int, u_int));
69 static void deflate_free __P((void *, void *));
70 static int deflate_common __P((struct mbuf *, struct mbuf *, size_t *, int));
71 static int deflate_compress __P((struct mbuf *, struct mbuf *, size_t *));
72 static int deflate_decompress __P((struct mbuf *, struct mbuf *, size_t *));
73
74 /*
75 * We need to use default window size (2^15 = 32Kbytes as of writing) for
76 * inbound case. Otherwise we get interop problem.
77 * Use negative value to avoid Adler32 checksum. This is an undocumented
78 * feature in zlib (see ipsec wg mailing list archive in January 2000).
79 */
80 static int deflate_policy = Z_DEFAULT_COMPRESSION;
81 static int deflate_window_out = -12;
82 static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */
83 static int deflate_memlevel = MAX_MEM_LEVEL;
84
85 static const struct ipcomp_algorithm ipcomp_algorithms[] = {
86 { deflate_compress, deflate_decompress, 90 },
87 };
88
89 const struct ipcomp_algorithm *
90 ipcomp_algorithm_lookup(idx)
91 int idx;
92 {
93
94 if (idx == SADB_X_CALG_DEFLATE)
95 return &ipcomp_algorithms[0];
96 return NULL;
97 }
98
99 static void *
100 deflate_alloc(aux, items, siz)
101 void *aux;
102 u_int items;
103 u_int siz;
104 {
105 void *ptr;
106 ptr = malloc(items * siz, M_TEMP, M_NOWAIT);
107 return ptr;
108 }
109
110 static void
111 deflate_free(aux, ptr)
112 void *aux;
113 void *ptr;
114 {
115 free(ptr, M_TEMP);
116 }
117
118 static int
119 deflate_common(m, md, lenp, mode)
120 struct mbuf *m;
121 struct mbuf *md;
122 size_t *lenp;
123 int mode; /* 0: compress 1: decompress */
124 {
125 struct mbuf *mprev;
126 struct mbuf *p;
127 struct mbuf *n = NULL, *n0 = NULL, **np;
128 z_stream zs;
129 int error = 0;
130 int zerror;
131 size_t offset;
132
133 #define MOREBLOCK() \
134 do { \
135 /* keep the reply buffer into our chain */ \
136 if (n) { \
137 n->m_len = zs.total_out - offset; \
138 offset = zs.total_out; \
139 *np = n; \
140 np = &n->m_next; \
141 n = NULL; \
142 } \
143 \
144 /* get a fresh reply buffer */ \
145 MGET(n, M_DONTWAIT, MT_DATA); \
146 if (n) { \
147 MCLGET(n, M_DONTWAIT); \
148 } \
149 if (!n) { \
150 error = ENOBUFS; \
151 goto fail; \
152 } \
153 n->m_len = 0; \
154 n->m_len = M_TRAILINGSPACE(n); \
155 n->m_next = NULL; \
156 /* \
157 * if this is the first reply buffer, reserve \
158 * region for ipcomp header. \
159 */ \
160 if (*np == NULL) { \
161 n->m_len -= sizeof(struct ipcomp); \
162 n->m_data += sizeof(struct ipcomp); \
163 } \
164 \
165 zs.next_out = mtod(n, u_int8_t *); \
166 zs.avail_out = n->m_len; \
167 } while (/*CONSTCOND*/ 0)
168
169 for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
170 ;
171 if (!mprev)
172 panic("md is not in m in deflate_common");
173
174 bzero(&zs, sizeof(zs));
175 zs.zalloc = deflate_alloc;
176 zs.zfree = deflate_free;
177
178 zerror = mode ? inflateInit2(&zs, deflate_window_in)
179 : deflateInit2(&zs, deflate_policy, Z_DEFLATED,
180 deflate_window_out, deflate_memlevel,
181 Z_DEFAULT_STRATEGY);
182 if (zerror != Z_OK) {
183 error = ENOBUFS;
184 goto fail;
185 }
186
187 n0 = n = NULL;
188 np = &n0;
189 offset = 0;
190 zerror = 0;
191 p = md;
192 while (p && p->m_len == 0) {
193 p = p->m_next;
194 }
195
196 /* input stream and output stream are available */
197 while (p && zs.avail_in == 0) {
198 /* get input buffer */
199 if (p && zs.avail_in == 0) {
200 zs.next_in = mtod(p, u_int8_t *);
201 zs.avail_in = p->m_len;
202 p = p->m_next;
203 while (p && p->m_len == 0) {
204 p = p->m_next;
205 }
206 }
207
208 /* get output buffer */
209 if (zs.next_out == NULL || zs.avail_out == 0) {
210 MOREBLOCK();
211 }
212
213 zerror = mode ? inflate(&zs, Z_NO_FLUSH)
214 : deflate(&zs, Z_NO_FLUSH);
215
216 if (zerror == Z_STREAM_END)
217 ; /* once more. */
218 else if (zerror == Z_OK) {
219 /* inflate: Z_OK can indicate the end of decode */
220 if (mode && !p && zs.avail_out != 0)
221 goto terminate;
222 else
223 ; /* once more. */
224 } else {
225 if (zs.msg) {
226 ipseclog((LOG_ERR, "ipcomp_%scompress: "
227 "%sflate(Z_NO_FLUSH): %s\n",
228 mode ? "de" : "", mode ? "in" : "de",
229 zs.msg));
230 } else {
231 ipseclog((LOG_ERR, "ipcomp_%scompress: "
232 "%sflate(Z_NO_FLUSH): unknown error (%d)\n",
233 mode ? "de" : "", mode ? "in" : "de",
234 zerror));
235 }
236 mode ? inflateEnd(&zs) : deflateEnd(&zs);
237 error = EINVAL;
238 goto fail;
239 }
240 }
241
242 if (zerror == Z_STREAM_END)
243 goto terminate;
244
245 /* termination */
246 while (1) {
247 /* get output buffer */
248 if (zs.next_out == NULL || zs.avail_out == 0) {
249 MOREBLOCK();
250 }
251
252 zerror = mode ? inflate(&zs, Z_SYNC_FLUSH)
253 : deflate(&zs, Z_FINISH);
254
255 if (zerror == Z_STREAM_END)
256 break;
257 else if (zerror == Z_OK) {
258 if (mode && zs.avail_out != 0)
259 goto terminate;
260 else
261 ; /* once more. */
262 } else {
263 if (zs.msg) {
264 ipseclog((LOG_ERR, "ipcomp_%scompress: "
265 "%sflate(Z_FINISH): %s\n",
266 mode ? "de" : "", mode ? "in" : "de",
267 zs.msg));
268 } else {
269 ipseclog((LOG_ERR, "ipcomp_%scompress: "
270 "%sflate(Z_FINISH): unknown error (%d)\n",
271 mode ? "de" : "", mode ? "in" : "de",
272 zerror));
273 }
274 mode ? inflateEnd(&zs) : deflateEnd(&zs);
275 error = EINVAL;
276 goto fail;
277 }
278 }
279
280 terminate:
281 zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs);
282 if (zerror != Z_OK) {
283 if (zs.msg) {
284 ipseclog((LOG_ERR, "ipcomp_%scompress: "
285 "%sflateEnd: %s\n",
286 mode ? "de" : "", mode ? "in" : "de",
287 zs.msg));
288 } else {
289 ipseclog((LOG_ERR, "ipcomp_%scompress: "
290 "%sflateEnd: unknown error (%d)\n",
291 mode ? "de" : "", mode ? "in" : "de",
292 zerror));
293 }
294 error = EINVAL;
295 goto fail;
296 }
297 /* keep the final reply buffer into our chain */
298 if (n) {
299 n->m_len = zs.total_out - offset;
300 offset = zs.total_out;
301 *np = n;
302 np = &n->m_next;
303 n = NULL;
304 }
305
306 /* switch the mbuf to the new one */
307 mprev->m_next = n0;
308 m_freem(md);
309 *lenp = zs.total_out;
310
311 return 0;
312
313 fail:
314 if (m)
315 m_freem(m);
316 if (n)
317 m_freem(n);
318 if (n0)
319 m_freem(n0);
320 return error;
321 #undef MOREBLOCK
322 }
323
324 static int
325 deflate_compress(m, md, lenp)
326 struct mbuf *m;
327 struct mbuf *md;
328 size_t *lenp;
329 {
330 if (!m)
331 panic("m == NULL in deflate_compress");
332 if (!md)
333 panic("md == NULL in deflate_compress");
334 if (!lenp)
335 panic("lenp == NULL in deflate_compress");
336
337 return deflate_common(m, md, lenp, 0);
338 }
339
340 static int
341 deflate_decompress(m, md, lenp)
342 struct mbuf *m;
343 struct mbuf *md;
344 size_t *lenp;
345 {
346 if (!m)
347 panic("m == NULL in deflate_decompress");
348 if (!md)
349 panic("md == NULL in deflate_decompress");
350 if (!lenp)
351 panic("lenp == NULL in deflate_decompress");
352
353 return deflate_common(m, md, lenp, 1);
354 }
Cache object: dcb52e45b9741ac36385b34224b4ea3b
|