1/* $OpenBSD: deflate.c,v 1.3 2001/08/20 02:45:22 hugh Exp $ */
2
3/*-
4 * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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 * 3. The name of the author may not be used to endorse or promote products
16 *   derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * This file contains a wrapper around the deflate algo compression
32 * functions using the zlib library (see sys/contrib/zlib)
33 */
34
35#include <sys/types.h>
36#include <sys/param.h>
37#include <sys/malloc.h>
38#include <sys/param.h>
39#include <sys/kernel.h>
40#include <sys/sdt.h>
41#include <sys/systm.h>
42#include <contrib/zlib/zlib.h>
43
44#include <opencrypto/cryptodev.h>
45#include <opencrypto/deflate.h>
46
47SDT_PROVIDER_DECLARE(opencrypto);
48SDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, entry,
49    "int", "uint32_t");
50SDT_PROBE_DEFINE6(opencrypto, deflate, deflate_global, bad,
51    "int", "int", "int", "int", "int", "int");
52SDT_PROBE_DEFINE6(opencrypto, deflate, deflate_global, iter,
53    "int", "int", "int", "int", "int", "int");
54SDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, return,
55    "int", "uint32_t");
56
57int window_inflate = -1 * MAX_WBITS;
58int window_deflate = -12;
59
60static void *
61crypto_zalloc(void *nil, u_int type, u_int size)
62{
63	void *ptr;
64
65	ptr = malloc(type *size, M_CRYPTO_DATA, M_NOWAIT);
66	return ptr;
67}
68
69static void
70crypto_zfree(void *nil, void *ptr)
71{
72
73	free(ptr, M_CRYPTO_DATA);
74}
75
76/*
77 * This function takes a block of data and (de)compress it using the deflate
78 * algorithm
79 */
80
81uint32_t
82deflate_global(uint8_t *data, uint32_t size, int decomp, uint8_t **out)
83{
84	/* decomp indicates whether we compress (0) or decompress (1) */
85
86	z_stream zbuf;
87	uint8_t *output;
88	uint32_t count, result;
89	int error, i;
90	struct deflate_buf *bufh, *bufp;
91
92	SDT_PROBE2(opencrypto, deflate, deflate_global, entry, decomp, size);
93
94	bufh = bufp = NULL;
95	if (!decomp) {
96		i = 1;
97	} else {
98		/*
99	 	 * Choose a buffer with 4x the size of the input buffer
100	 	 * for the size of the output buffer in the case of
101	 	 * decompression. If it's not sufficient, it will need to be
102	 	 * updated while the decompression is going on.
103	 	 */
104		i = 4;
105	}
106	/*
107	 * Make sure we do have enough output space.  Repeated calls to
108	 * deflate need at least 6 bytes of output buffer space to avoid
109	 * repeated markers.  We will always provide at least 16 bytes.
110	 */
111	while ((size * i) < 16)
112		i++;
113
114	bufh = bufp = malloc(sizeof(*bufp) + (size_t)(size * i),
115	    M_CRYPTO_DATA, M_NOWAIT);
116	if (bufp == NULL) {
117		SDT_PROBE6(opencrypto, deflate, deflate_global, bad,
118		    decomp, 0, __LINE__, 0, 0, 0);
119		goto bad2;
120	}
121	bufp->next = NULL;
122	bufp->size = size * i;
123
124	bzero(&zbuf, sizeof(z_stream));
125	zbuf.zalloc = crypto_zalloc;
126	zbuf.zfree = crypto_zfree;
127	zbuf.opaque = Z_NULL;
128	zbuf.next_in = data;	/* Data that is going to be processed. */
129	zbuf.avail_in = size;	/* Total length of data to be processed. */
130	zbuf.next_out = bufp->data;
131	zbuf.avail_out = bufp->size;
132
133	error = decomp ? inflateInit2(&zbuf, window_inflate) :
134	    deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD,
135		    window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY);
136	if (error != Z_OK) {
137		SDT_PROBE6(opencrypto, deflate, deflate_global, bad,
138		    decomp, error, __LINE__, 0, 0, 0);
139		goto bad;
140	}
141
142	for (;;) {
143		error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) :
144				 deflate(&zbuf, Z_FINISH);
145		if (error != Z_OK && error != Z_STREAM_END) {
146			SDT_PROBE6(opencrypto, deflate, deflate_global, bad,
147			    decomp, error, __LINE__,
148			    zbuf.avail_in, zbuf.avail_out, zbuf.total_out);
149			goto bad;
150		}
151		SDT_PROBE6(opencrypto, deflate, deflate_global, iter,
152		    decomp, error, __LINE__,
153		    zbuf.avail_in, zbuf.avail_out, zbuf.total_out);
154		if (decomp && zbuf.avail_in == 0 && error == Z_STREAM_END) {
155			/* Done. */
156			break;
157		} else if (!decomp && error == Z_STREAM_END) {
158			/* Done. */
159			break;
160		} else if (zbuf.avail_out == 0) {
161			struct deflate_buf *p;
162
163			/* We need more output space for another iteration. */
164			p = malloc(sizeof(*p) + (size_t)(size * i),
165			    M_CRYPTO_DATA, M_NOWAIT);
166			if (p == NULL) {
167				SDT_PROBE6(opencrypto, deflate, deflate_global,
168				    bad, decomp, 0, __LINE__, 0, 0, 0);
169				goto bad;
170			}
171			p->next = NULL;
172			p->size = size * i;
173			bufp->next = p;
174			bufp = p;
175			zbuf.next_out = bufp->data;
176			zbuf.avail_out = bufp->size;
177		} else {
178			/* Unexpect result. */
179			SDT_PROBE6(opencrypto, deflate, deflate_global,
180			    bad, decomp, error, __LINE__,
181			    zbuf.avail_in, zbuf.avail_out, zbuf.total_out);
182			goto bad;
183		}
184	}
185
186	result = count = zbuf.total_out;
187
188	*out = malloc(result, M_CRYPTO_DATA, M_NOWAIT);
189	if (*out == NULL) {
190		SDT_PROBE6(opencrypto, deflate, deflate_global, bad,
191		    decomp, 0, __LINE__, 0, 0, 0);
192		goto bad;
193	}
194	if (decomp)
195		inflateEnd(&zbuf);
196	else
197		deflateEnd(&zbuf);
198	output = *out;
199	for (bufp = bufh; bufp != NULL; ) {
200		if (count > bufp->size) {
201			struct deflate_buf *p;
202
203			bcopy(bufp->data, *out, bufp->size);
204			*out += bufp->size;
205			count -= bufp->size;
206			p = bufp;
207			bufp = bufp->next;
208			free(p, M_CRYPTO_DATA);
209		} else {
210			/* It should be the last buffer. */
211			bcopy(bufp->data, *out, count);
212			*out += count;
213			free(bufp, M_CRYPTO_DATA);
214			bufp = NULL;
215			count = 0;
216		}
217	}
218	*out = output;
219	SDT_PROBE2(opencrypto, deflate, deflate_global, return, decomp, result);
220	return result;
221
222bad:
223	if (decomp)
224		inflateEnd(&zbuf);
225	else
226		deflateEnd(&zbuf);
227	for (bufp = bufh; bufp != NULL; ) {
228		struct deflate_buf *p;
229
230		p = bufp;
231		bufp = bufp->next;
232		free(p, M_CRYPTO_DATA);
233	}
234bad2:
235	*out = NULL;
236	return 0;
237}
238