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