1 | /* $NetBSD: deflate.c,v 1.22 2015/03/26 17:40:16 prlw1 Exp $ */ |
2 | /* $FreeBSD: src/sys/opencrypto/deflate.c,v 1.1.2.1 2002/11/21 23:34:23 sam Exp $ */ |
3 | /* $OpenBSD: deflate.c,v 1.3 2001/08/20 02:45:22 hugh Exp $ */ |
4 | |
5 | /* |
6 | * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org) |
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 | * |
12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. The name of the author may not be used to endorse or promote products |
18 | * derived from this software without specific prior written permission. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
22 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
23 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
24 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
29 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * This file contains a wrapper around the deflate algo compression |
34 | * functions using the zlib library (see net/zlib.{c,h}) |
35 | */ |
36 | |
37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: deflate.c,v 1.22 2015/03/26 17:40:16 prlw1 Exp $" ); |
39 | |
40 | #include <sys/types.h> |
41 | #include <sys/malloc.h> |
42 | #include <sys/param.h> |
43 | #include <sys/systm.h> |
44 | #include <net/zlib.h> |
45 | |
46 | #include <opencrypto/cryptodev.h> |
47 | #include <opencrypto/deflate.h> |
48 | |
49 | #define ZBUF 10 |
50 | |
51 | struct deflate_buf { |
52 | u_int8_t *out; |
53 | u_int32_t size; |
54 | }; |
55 | |
56 | int window_inflate = -1 * MAX_WBITS; |
57 | int window_deflate = -12; |
58 | |
59 | /* |
60 | * This function takes a block of data and (de)compress it using the deflate |
61 | * algorithm |
62 | */ |
63 | |
64 | static void * |
65 | ocf_zalloc(void *nil, u_int type, u_int size) |
66 | { |
67 | void *ptr; |
68 | |
69 | ptr = malloc(type *size, M_CRYPTO_DATA, M_NOWAIT); |
70 | return ptr; |
71 | } |
72 | |
73 | static void |
74 | ocf_zfree(void *nil, void *ptr) |
75 | { |
76 | free(ptr, M_CRYPTO_DATA); |
77 | } |
78 | |
79 | u_int32_t |
80 | deflate_global(u_int8_t *data, u_int32_t size, int decomp, u_int8_t **out, |
81 | int size_hint) |
82 | { |
83 | /* decomp indicates whether we compress (0) or decompress (1) */ |
84 | |
85 | z_stream zbuf; |
86 | u_int8_t *output; |
87 | u_int32_t count, result, tocopy; |
88 | int error, i, j; |
89 | struct deflate_buf buf[ZBUF]; |
90 | |
91 | DPRINTF(("deflate_global: size %u\n" , size)); |
92 | |
93 | memset(&zbuf, 0, sizeof(z_stream)); |
94 | zbuf.next_in = data; /* data that is going to be processed */ |
95 | zbuf.zalloc = ocf_zalloc; |
96 | zbuf.zfree = ocf_zfree; |
97 | zbuf.opaque = Z_NULL; |
98 | zbuf.avail_in = size; /* Total length of data to be processed */ |
99 | |
100 | if (!decomp) { |
101 | buf[0].size = size; |
102 | } else { |
103 | /* |
104 | * Choose a buffer with 4x the size of the input buffer |
105 | * for the size of the output buffer in the case of |
106 | * decompression. If it's not sufficient, it will need to be |
107 | * updated while the decompression is going on |
108 | */ |
109 | |
110 | buf[0].size = MAX(size * 4, size_hint); |
111 | } |
112 | buf[0].out = malloc(buf[0].size, M_CRYPTO_DATA, M_NOWAIT); |
113 | if (buf[0].out == NULL) |
114 | return 0; |
115 | i = 1; |
116 | |
117 | zbuf.next_out = buf[0].out; |
118 | zbuf.avail_out = buf[0].size; |
119 | |
120 | error = decomp ? inflateInit2(&zbuf, window_inflate) : |
121 | deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD, |
122 | window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY); |
123 | |
124 | if (error != Z_OK) |
125 | goto bad2; |
126 | for (;;) { |
127 | error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) : |
128 | deflate(&zbuf, Z_FINISH); |
129 | if (error == Z_STREAM_END) /* success */ |
130 | break; |
131 | /* |
132 | * XXX compensate for two problems: |
133 | * -Former versions of this code didn't set Z_FINISH |
134 | * on compression, so the compressed data are not correctly |
135 | * terminated and the decompressor doesn't get Z_STREAM_END. |
136 | * Accept such packets for interoperability. |
137 | * -sys/net/zlib.c has a bug which makes that Z_BUF_ERROR is |
138 | * set after successful decompression under rare conditions. |
139 | */ |
140 | else if (decomp && (error == Z_OK || error == Z_BUF_ERROR) |
141 | && zbuf.avail_in == 0 && zbuf.avail_out != 0) |
142 | break; |
143 | else if (error != Z_OK) |
144 | goto bad; |
145 | else if (zbuf.avail_out == 0) { |
146 | /* we need more output space, allocate size */ |
147 | int nextsize = buf[i-1].size * 2; |
148 | if (i == ZBUF || nextsize > 1000000) |
149 | goto bad; |
150 | buf[i].out = malloc(nextsize, M_CRYPTO_DATA, M_NOWAIT); |
151 | if (buf[i].out == NULL) |
152 | goto bad; |
153 | zbuf.next_out = buf[i].out; |
154 | zbuf.avail_out = buf[i].size = nextsize; |
155 | i++; |
156 | } |
157 | } |
158 | |
159 | result = count = zbuf.total_out; |
160 | |
161 | if (i != 1) { /* copy everything into one buffer */ |
162 | output = malloc(result, M_CRYPTO_DATA, M_NOWAIT); |
163 | if (output == NULL) |
164 | goto bad; |
165 | *out = output; |
166 | for (j = 0; j < i; j++) { |
167 | tocopy = MIN(count, buf[j].size); |
168 | /* XXX the last buf can be empty */ |
169 | KASSERT(tocopy || j == (i - 1)); |
170 | memcpy(output, buf[j].out, tocopy); |
171 | output += tocopy; |
172 | free(buf[j].out, M_CRYPTO_DATA); |
173 | count -= tocopy; |
174 | } |
175 | KASSERT(count == 0); |
176 | } else { |
177 | *out = buf[0].out; |
178 | } |
179 | if (decomp) |
180 | inflateEnd(&zbuf); |
181 | else |
182 | deflateEnd(&zbuf); |
183 | return result; |
184 | |
185 | bad: |
186 | if (decomp) |
187 | inflateEnd(&zbuf); |
188 | else |
189 | deflateEnd(&zbuf); |
190 | bad2: |
191 | for (j = 0; j < i; j++) |
192 | free(buf[j].out, M_CRYPTO_DATA); |
193 | return 0; |
194 | } |
195 | |
196 | /* |
197 | * Initial version will perform a single gzip encapsulation, |
198 | * filling in the header, |
199 | * and appending the crc and uncompressed length. |
200 | * |
201 | * Later version will support multiple buffers with |
202 | * a flag indication final buffer. The crc is maintained |
203 | * over all buffers and appended to the output along with |
204 | * the uncompressed length after the final data buffer |
205 | * has been compressed and output. |
206 | * |
207 | * Ditto for uncompress - CRC is extracted from the final packed |
208 | * and compared against CRC of uncompressed data. |
209 | * |
210 | */ |
211 | |
212 | /* constant header for the gzip */ |
213 | static const char [10] = { |
214 | 0x1f, 0x8b, /* ID1 ID2 */ |
215 | Z_DEFLATED, /* CM */ |
216 | 0, /* FLG */ |
217 | 0, 0, 0, 0, /* MTIME */ |
218 | 0, /* XFL */ |
219 | 0x03 /* OS (Unix) */ |
220 | }; |
221 | |
222 | /* Followed by compressed payload */ |
223 | /* Followed by uint32_t CRC32 and uint32_t ISIZE */ |
224 | #define GZIP_TAIL_SIZE 8 |
225 | |
226 | u_int32_t |
227 | gzip_global(u_int8_t *data, u_int32_t size, |
228 | int decomp, u_int8_t **out, int size_hint) |
229 | { |
230 | /* decomp indicates whether we compress (0) or decompress (1) */ |
231 | z_stream zbuf; |
232 | u_int8_t *output; |
233 | u_int32_t count, result; |
234 | int error, i, j; |
235 | struct deflate_buf buf[ZBUF]; |
236 | u_int32_t crc; |
237 | u_int32_t isize = 0, icrc = 0; |
238 | |
239 | DPRINTF(("gzip_global: decomp %d, size %u\n" , decomp, size)); |
240 | |
241 | memset(&zbuf, 0, sizeof(z_stream)); |
242 | zbuf.zalloc = ocf_zalloc; |
243 | zbuf.zfree = ocf_zfree; |
244 | zbuf.opaque = Z_NULL; |
245 | |
246 | if (!decomp) { |
247 | /* compress */ |
248 | DPRINTF(("gzip_global: compress malloc %u + %zu + %u = %zu\n" , |
249 | size, sizeof(gzip_header), GZIP_TAIL_SIZE, |
250 | size + sizeof(gzip_header) + GZIP_TAIL_SIZE)); |
251 | |
252 | buf[0].size = size; |
253 | crc = crc32(0, data, size); |
254 | DPRINTF(("gzip_compress: size %u, crc 0x%x\n" , size, crc)); |
255 | zbuf.avail_in = size; /* Total length of data to be processed */ |
256 | zbuf.next_in = data; /* data that is going to be processed */ |
257 | } else { |
258 | /* decompress */ |
259 | /* check the gzip header */ |
260 | if (size <= sizeof(gzip_header) + GZIP_TAIL_SIZE) { |
261 | /* Not enough data for the header & tail */ |
262 | DPRINTF(("gzip_global: not enough data (%u)\n" , |
263 | size)); |
264 | return 0; |
265 | } |
266 | |
267 | /* XXX this is pretty basic, |
268 | * needs to be expanded to ignore MTIME, OS, |
269 | * but still ensure flags are 0. |
270 | * Q. Do we need to support the flags and |
271 | * optional header fields? Likely. |
272 | * XXX add flag and field support too. |
273 | */ |
274 | if (memcmp(data, gzip_header, sizeof(gzip_header)) != 0) { |
275 | DPRINTF(("gzip_global: unsupported gzip header (%02x%02x)\n" , |
276 | data[0], data[1])); |
277 | return 0; |
278 | } else { |
279 | DPRINTF(("gzip_global.%d: gzip header ok\n" ,__LINE__)); |
280 | } |
281 | |
282 | memcpy(&isize, &data[size-sizeof(uint32_t)], sizeof(uint32_t)); |
283 | LE32TOH(isize); |
284 | memcpy(&icrc, &data[size-2*sizeof(uint32_t)], sizeof(uint32_t)); |
285 | LE32TOH(icrc); |
286 | |
287 | DPRINTF(("gzip_global: isize = %u (%02x %02x %02x %02x)\n" , |
288 | isize, |
289 | data[size-4], |
290 | data[size-3], |
291 | data[size-2], |
292 | data[size-1])); |
293 | |
294 | buf[0].size = isize; |
295 | crc = crc32(0, NULL, 0); /* get initial crc value */ |
296 | |
297 | /* skip over the gzip header */ |
298 | zbuf.next_in = data + sizeof(gzip_header); |
299 | |
300 | /* actual payload size stripped of gzip header and tail */ |
301 | zbuf.avail_in = size - sizeof(gzip_header) - GZIP_TAIL_SIZE; |
302 | } |
303 | |
304 | buf[0].out = malloc(buf[0].size, M_CRYPTO_DATA, M_NOWAIT); |
305 | if (buf[0].out == NULL) |
306 | return 0; |
307 | zbuf.next_out = buf[0].out; |
308 | zbuf.avail_out = buf[0].size; |
309 | DPRINTF(("zbuf avail_in %u, avail_out %u\n" , |
310 | zbuf.avail_in, zbuf.avail_out)); |
311 | i = 1; |
312 | |
313 | error = decomp ? inflateInit2(&zbuf, window_inflate) : |
314 | deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD, |
315 | window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY); |
316 | |
317 | if (error != Z_OK) { |
318 | printf("deflateInit2() failed\n" ); |
319 | goto bad2; |
320 | } |
321 | for (;;) { |
322 | DPRINTF(("pre: %s in:%u out:%u\n" , decomp ? "deflate()" : "inflate()" , |
323 | zbuf.avail_in, zbuf.avail_out)); |
324 | error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) : |
325 | deflate(&zbuf, Z_FINISH); |
326 | DPRINTF(("post: %s in:%u out:%u\n" , decomp ? "deflate()" : "inflate()" , |
327 | zbuf.avail_in, zbuf.avail_out)); |
328 | if (error == Z_STREAM_END) /* success */ |
329 | break; |
330 | /* |
331 | * XXX compensate for a zlib problem: |
332 | * -sys/net/zlib.c has a bug which makes that Z_BUF_ERROR is |
333 | * set after successful decompression under rare conditions. |
334 | */ |
335 | else if (decomp && error == Z_BUF_ERROR |
336 | && zbuf.avail_in == 0 && zbuf.avail_out != 0) |
337 | break; |
338 | else if (error != Z_OK) |
339 | goto bad; |
340 | else if (zbuf.avail_out == 0) { |
341 | /* we need more output space, allocate size */ |
342 | int nextsize = buf[i-1].size * 2; |
343 | if (i == ZBUF || nextsize > 1000000) |
344 | goto bad; |
345 | buf[i].out = malloc(nextsize, M_CRYPTO_DATA, M_NOWAIT); |
346 | if (buf[i].out == NULL) |
347 | goto bad; |
348 | zbuf.next_out = buf[i].out; |
349 | zbuf.avail_out = buf[i].size = nextsize; |
350 | i++; |
351 | } |
352 | } |
353 | |
354 | if (decomp) { |
355 | count = result = zbuf.total_out; |
356 | } else { |
357 | /* need room for header, CRC, and ISIZE */ |
358 | result = zbuf.total_out + sizeof(gzip_header) + GZIP_TAIL_SIZE; |
359 | count = zbuf.total_out; |
360 | } |
361 | |
362 | DPRINTF(("gzip_global: in %u -> out %u\n" , size, result)); |
363 | |
364 | *out = malloc(result, M_CRYPTO_DATA, M_NOWAIT); |
365 | if (*out == NULL) |
366 | goto bad; |
367 | output = *out; |
368 | if (decomp) |
369 | inflateEnd(&zbuf); |
370 | else { |
371 | deflateEnd(&zbuf); |
372 | |
373 | /* fill in gzip header */ |
374 | memcpy(output, gzip_header, sizeof(gzip_header)); |
375 | output += sizeof(gzip_header); |
376 | } |
377 | for (j = 0; j < i; j++) { |
378 | if (decomp) { |
379 | /* update crc for decompressed data */ |
380 | crc = crc32(crc, buf[j].out, MIN(count, buf[j].size)); |
381 | } |
382 | if (count > buf[j].size) { |
383 | memcpy(output, buf[j].out, buf[j].size); |
384 | output += buf[j].size; |
385 | free(buf[j].out, M_CRYPTO_DATA); |
386 | count -= buf[j].size; |
387 | } else { |
388 | /* it should be the last buffer */ |
389 | memcpy(output, buf[j].out, count); |
390 | output += count; |
391 | free(buf[j].out, M_CRYPTO_DATA); |
392 | count = 0; |
393 | } |
394 | } |
395 | |
396 | if (!decomp) { |
397 | /* fill in CRC and ISIZE */ |
398 | HTOLE32(crc); |
399 | memcpy(output, &crc, sizeof(uint32_t)); |
400 | HTOLE32(size); |
401 | memcpy(output + sizeof(uint32_t), &size, sizeof(uint32_t)); |
402 | |
403 | DPRINTF(("gzip_global: size = 0x%x (%02x %02x %02x %02x)\n" , |
404 | size, |
405 | output[7], |
406 | output[3], |
407 | output[5], |
408 | output[4])); |
409 | } else { |
410 | if (crc != icrc || result != isize) { |
411 | DPRINTF(("gzip_global: crc/size mismatch\n" )); |
412 | free(*out, M_CRYPTO_DATA); |
413 | *out = NULL; |
414 | return 0; |
415 | } |
416 | } |
417 | |
418 | return result; |
419 | |
420 | bad: |
421 | if (decomp) |
422 | inflateEnd(&zbuf); |
423 | else |
424 | deflateEnd(&zbuf); |
425 | bad2: |
426 | *out = NULL; |
427 | for (j = 0; j < i; j++) |
428 | free(buf[j].out, M_CRYPTO_DATA); |
429 | return 0; |
430 | } |
431 | |