1 /* $FreeBSD: releng/5.0/sys/netinet6/ipcomp_core.c 96457 2002-05-12 14:12:30Z ume $ */
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 "opt_inet.h"
38 #include "opt_inet6.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/mbuf.h>
44 #include <sys/domain.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/errno.h>
48 #include <sys/time.h>
49 #include <sys/syslog.h>
50 #include <sys/queue.h>
51
52 #include <net/if.h>
53 #include <net/route.h>
54 #include <net/netisr.h>
55 #include <net/zlib.h>
56 #include <machine/cpu.h>
57
58 #include <netinet6/ipcomp.h>
59 #ifdef INET6
60 #include <netinet6/ipcomp6.h>
61 #endif
62 #include <netinet6/ipsec.h>
63 #ifdef INET6
64 #include <netinet6/ipsec6.h>
65 #endif
66
67 #include <machine/stdarg.h>
68
69 #include <net/net_osdep.h>
70
71 static void *deflate_alloc __P((void *, u_int, u_int));
72 static void deflate_free __P((void *, void *));
73 static int deflate_common __P((struct mbuf *, struct mbuf *, size_t *, int));
74 static int deflate_compress __P((struct mbuf *, struct mbuf *, size_t *));
75 static int deflate_decompress __P((struct mbuf *, struct mbuf *, size_t *));
76
77 /*
78 * We need to use default window size (2^15 = 32Kbytes as of writing) for
79 * inbound case. Otherwise we get interop problem.
80 * Use negative value to avoid Adler32 checksum. This is an undocumented
81 * feature in zlib (see ipsec wg mailing list archive in January 2000).
82 */
83 static int deflate_policy = Z_DEFAULT_COMPRESSION;
84 static int deflate_window_out = -12;
85 static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */
86 static int deflate_memlevel = MAX_MEM_LEVEL;
87
88 static const struct ipcomp_algorithm ipcomp_algorithms[] = {
89 { deflate_compress, deflate_decompress, 90 },
90 };
91
92 const struct ipcomp_algorithm *
93 ipcomp_algorithm_lookup(idx)
94 int idx;
95 {
96
97 if (idx == SADB_X_CALG_DEFLATE)
98 return &ipcomp_algorithms[0];
99 return NULL;
100 }
101
102 static void *
103 deflate_alloc(aux, items, siz)
104 void *aux;
105 u_int items;
106 u_int siz;
107 {
108 void *ptr;
109 ptr = malloc(items * siz, M_TEMP, M_NOWAIT);
110 return ptr;
111 }
112
113 static void
114 deflate_free(aux, ptr)
115 void *aux;
116 void *ptr;
117 {
118 free(ptr, M_TEMP);
119 }
120
121 static int
122 deflate_common(m, md, lenp, mode)
123 struct mbuf *m;
124 struct mbuf *md;
125 size_t *lenp;
126 int mode; /* 0: compress 1: decompress */
127 {
128 struct mbuf *mprev;
129 struct mbuf *p;
130 struct mbuf *n = NULL, *n0 = NULL, **np;
131 z_stream zs;
132 int error = 0;
133 int zerror;
134 size_t offset;
135
136 #define MOREBLOCK() \
137 do { \
138 /* keep the reply buffer into our chain */ \
139 if (n) { \
140 n->m_len = zs.total_out - offset; \
141 offset = zs.total_out; \
142 *np = n; \
143 np = &n->m_next; \
144 n = NULL; \
145 } \
146 \
147 /* get a fresh reply buffer */ \
148 MGET(n, M_DONTWAIT, MT_DATA); \
149 if (n) { \
150 MCLGET(n, M_DONTWAIT); \
151 } \
152 if (!n) { \
153 error = ENOBUFS; \
154 goto fail; \
155 } \
156 n->m_len = 0; \
157 n->m_len = M_TRAILINGSPACE(n); \
158 n->m_next = NULL; \
159 /* \
160 * if this is the first reply buffer, reserve \
161 * region for ipcomp header. \
162 */ \
163 if (*np == NULL) { \
164 n->m_len -= sizeof(struct ipcomp); \
165 n->m_data += sizeof(struct ipcomp); \
166 } \
167 \
168 zs.next_out = mtod(n, u_int8_t *); \
169 zs.avail_out = n->m_len; \
170 } while (0)
171
172 for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
173 ;
174 if (!mprev)
175 panic("md is not in m in deflate_common");
176
177 bzero(&zs, sizeof(zs));
178 zs.zalloc = deflate_alloc;
179 zs.zfree = deflate_free;
180
181 zerror = mode ? inflateInit2(&zs, deflate_window_in)
182 : deflateInit2(&zs, deflate_policy, Z_DEFLATED,
183 deflate_window_out, deflate_memlevel,
184 Z_DEFAULT_STRATEGY);
185 if (zerror != Z_OK) {
186 error = ENOBUFS;
187 goto fail;
188 }
189
190 n0 = n = NULL;
191 np = &n0;
192 offset = 0;
193 zerror = 0;
194 p = md;
195 while (p && p->m_len == 0) {
196 p = p->m_next;
197 }
198
199 /* input stream and output stream are available */
200 while (p && zs.avail_in == 0) {
201 /* get input buffer */
202 if (p && zs.avail_in == 0) {
203 zs.next_in = mtod(p, u_int8_t *);
204 zs.avail_in = p->m_len;
205 p = p->m_next;
206 while (p && p->m_len == 0) {
207 p = p->m_next;
208 }
209 }
210
211 /* get output buffer */
212 if (zs.next_out == NULL || zs.avail_out == 0) {
213 MOREBLOCK();
214 }
215
216 zerror = mode ? inflate(&zs, Z_NO_FLUSH)
217 : deflate(&zs, Z_NO_FLUSH);
218
219 if (zerror == Z_STREAM_END)
220 ; /* once more. */
221 else if (zerror == Z_OK) {
222 /* inflate: Z_OK can indicate the end of decode */
223 if (mode && !p && zs.avail_out != 0)
224 goto terminate;
225 else
226 ; /* once more. */
227 } else {
228 if (zs.msg) {
229 ipseclog((LOG_ERR, "ipcomp_%scompress: "
230 "%sflate(Z_NO_FLUSH): %s\n",
231 mode ? "de" : "", mode ? "in" : "de",
232 zs.msg));
233 } else {
234 ipseclog((LOG_ERR, "ipcomp_%scompress: "
235 "%sflate(Z_NO_FLUSH): unknown error (%d)\n",
236 mode ? "de" : "", mode ? "in" : "de",
237 zerror));
238 }
239 mode ? inflateEnd(&zs) : deflateEnd(&zs);
240 error = EINVAL;
241 goto fail;
242 }
243 }
244
245 if (zerror == Z_STREAM_END)
246 goto terminate;
247
248 /* termination */
249 while (1) {
250 /* get output buffer */
251 if (zs.next_out == NULL || zs.avail_out == 0) {
252 MOREBLOCK();
253 }
254
255 zerror = mode ? inflate(&zs, Z_SYNC_FLUSH)
256 : deflate(&zs, Z_FINISH);
257
258 if (zerror == Z_STREAM_END)
259 break;
260 else if (zerror == Z_OK) {
261 if (mode && zs.avail_out != 0)
262 goto terminate;
263 else
264 ; /* once more. */
265 } else {
266 if (zs.msg) {
267 ipseclog((LOG_ERR, "ipcomp_%scompress: "
268 "%sflate(Z_FINISH): %s\n",
269 mode ? "de" : "", mode ? "in" : "de",
270 zs.msg));
271 } else {
272 ipseclog((LOG_ERR, "ipcomp_%scompress: "
273 "%sflate(Z_FINISH): unknown error (%d)\n",
274 mode ? "de" : "", mode ? "in" : "de",
275 zerror));
276 }
277 mode ? inflateEnd(&zs) : deflateEnd(&zs);
278 error = EINVAL;
279 goto fail;
280 }
281 }
282
283 terminate:
284 zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs);
285 if (zerror != Z_OK) {
286 if (zs.msg) {
287 ipseclog((LOG_ERR, "ipcomp_%scompress: "
288 "%sflateEnd: %s\n",
289 mode ? "de" : "", mode ? "in" : "de",
290 zs.msg));
291 } else {
292 ipseclog((LOG_ERR, "ipcomp_%scompress: "
293 "%sflateEnd: unknown error (%d)\n",
294 mode ? "de" : "", mode ? "in" : "de",
295 zerror));
296 }
297 error = EINVAL;
298 goto fail;
299 }
300 /* keep the final reply buffer into our chain */
301 if (n) {
302 n->m_len = zs.total_out - offset;
303 offset = zs.total_out;
304 *np = n;
305 np = &n->m_next;
306 n = NULL;
307 }
308
309 /* switch the mbuf to the new one */
310 mprev->m_next = n0;
311 m_freem(md);
312 *lenp = zs.total_out;
313
314 return 0;
315
316 fail:
317 if (m)
318 m_freem(m);
319 if (n)
320 m_freem(n);
321 if (n0)
322 m_freem(n0);
323 return error;
324 #undef MOREBLOCK
325 }
326
327 static int
328 deflate_compress(m, md, lenp)
329 struct mbuf *m;
330 struct mbuf *md;
331 size_t *lenp;
332 {
333 if (!m)
334 panic("m == NULL in deflate_compress");
335 if (!md)
336 panic("md == NULL in deflate_compress");
337 if (!lenp)
338 panic("lenp == NULL in deflate_compress");
339
340 return deflate_common(m, md, lenp, 0);
341 }
342
343 static int
344 deflate_decompress(m, md, lenp)
345 struct mbuf *m;
346 struct mbuf *md;
347 size_t *lenp;
348 {
349 if (!m)
350 panic("m == NULL in deflate_decompress");
351 if (!md)
352 panic("md == NULL in deflate_decompress");
353 if (!lenp)
354 panic("lenp == NULL in deflate_decompress");
355
356 return deflate_common(m, md, lenp, 1);
357 }
Cache object: 27e0e10e1e00a0892b9f782cc9942af4
|