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 net/zlib.{c,h})
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD$");
37
38#include "opt_kdtrace.h"
39
40#include <sys/types.h>
41#include <sys/param.h>
42#include <sys/malloc.h>
43#include <sys/param.h>
44#include <sys/kernel.h>
45#include <sys/sdt.h>
46#include <sys/systm.h>
47#include <net/zlib.h>
48
49#include <opencrypto/cryptodev.h>
50#include <opencrypto/deflate.h>
51
52SDT_PROVIDER_DECLARE(opencrypto);
53SDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, entry,
54    "int", "u_int32_t");
55SDT_PROBE_DEFINE5(opencrypto, deflate, deflate_global, bad,
56    "int", "int", "int", "int", "int");
57SDT_PROBE_DEFINE5(opencrypto, deflate, deflate_global, iter,
58    "int", "int", "int", "int", "int");
59SDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, return,
60    "int", "u_int32_t");
61
62int window_inflate = -1 * MAX_WBITS;
63int window_deflate = -12;
64
65/*
66 * This function takes a block of data and (de)compress it using the deflate
67 * algorithm
68 */
69
70u_int32_t
71deflate_global(data, size, decomp, out)
72	u_int8_t *data;
73	u_int32_t size;
74	int decomp;
75	u_int8_t **out;
76{
77	/* decomp indicates whether we compress (0) or decompress (1) */
78
79	z_stream zbuf;
80	u_int8_t *output;
81	u_int32_t count, result;
82	int error, i;
83	struct deflate_buf *bufh, *bufp;
84
85	SDT_PROBE2(opencrypto, deflate, deflate_global, entry, decomp, size);
86
87	bufh = bufp = NULL;
88	if (!decomp) {
89		i = 1;
90	} else {
91		/*
92	 	 * Choose a buffer with 4x the size of the input buffer
93	 	 * for the size of the output buffer in the case of
94	 	 * decompression. If it's not sufficient, it will need to be
95	 	 * updated while the decompression is going on.
96	 	 */
97		i = 4;
98	}
99	/*
100	 * Make sure we do have enough output space.  Repeated calls to
101	 * deflate need at least 6 bytes of output buffer space to avoid
102	 * repeated markers.  We will always provide at least 16 bytes.
103	 */
104	while ((size * i) < 16)
105		i++;
106
107	bufh = bufp = malloc(sizeof(*bufp) + (size_t)(size * i),
108	    M_CRYPTO_DATA, M_NOWAIT);
109	if (bufp == NULL) {
110		SDT_PROBE3(opencrypto, deflate, deflate_global, bad,
111		    decomp, 0, __LINE__);
112		goto bad2;
113	}
114	bufp->next = NULL;
115	bufp->size = size * i;
116
117	bzero(&zbuf, sizeof(z_stream));
118	zbuf.zalloc = z_alloc;
119	zbuf.zfree = z_free;
120	zbuf.opaque = Z_NULL;
121	zbuf.next_in = data;	/* Data that is going to be processed. */
122	zbuf.avail_in = size;	/* Total length of data to be processed. */
123	zbuf.next_out = bufp->data;
124	zbuf.avail_out = bufp->size;
125
126	error = decomp ? inflateInit2(&zbuf, window_inflate) :
127	    deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD,
128		    window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY);
129	if (error != Z_OK) {
130		SDT_PROBE3(opencrypto, deflate, deflate_global, bad,
131		    decomp, error, __LINE__);
132		goto bad;
133	}
134
135	for (;;) {
136		error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) :
137				 deflate(&zbuf, Z_FINISH);
138		if (error != Z_OK && error != Z_STREAM_END) {
139			/*
140			 * Unfortunately we are limited to 5 arguments,
141			 * thus use two probes.
142			 */
143			SDT_PROBE5(opencrypto, deflate, deflate_global, bad,
144			    decomp, error, __LINE__,
145			    zbuf.avail_in, zbuf.avail_out);
146			SDT_PROBE5(opencrypto, deflate, deflate_global, bad,
147			    decomp, error, __LINE__,
148			    zbuf.state->dummy, zbuf.total_out);
149			goto bad;
150		}
151		SDT_PROBE5(opencrypto, deflate, deflate_global, iter,
152		    decomp, error, __LINE__,
153		    zbuf.avail_in, zbuf.avail_out);
154		SDT_PROBE5(opencrypto, deflate, deflate_global, iter,
155		    decomp, error, __LINE__,
156		    zbuf.state->dummy, zbuf.total_out);
157		if (decomp && zbuf.avail_in == 0 && error == Z_STREAM_END) {
158			/* Done. */
159			break;
160		} else if (!decomp && error == Z_STREAM_END) {
161			/* Done. */
162			break;
163		} else if (zbuf.avail_out == 0) {
164			struct deflate_buf *p;
165
166			/* We need more output space for another iteration. */
167			p = malloc(sizeof(*p) + (size_t)(size * i),
168			    M_CRYPTO_DATA, M_NOWAIT);
169			if (p == NULL) {
170				SDT_PROBE3(opencrypto, deflate, deflate_global,
171				    bad, decomp, 0, __LINE__);
172				goto bad;
173			}
174			p->next = NULL;
175			p->size = size * i;
176			bufp->next = p;
177			bufp = p;
178			zbuf.next_out = bufp->data;
179			zbuf.avail_out = bufp->size;
180		} else {
181			/* Unexpect result. */
182			/*
183			 * Unfortunately we are limited to 5 arguments,
184			 * thus, again, use two probes.
185			 */
186			SDT_PROBE5(opencrypto, deflate, deflate_global, bad,
187			    decomp, error, __LINE__,
188			    zbuf.avail_in, zbuf.avail_out);
189			SDT_PROBE5(opencrypto, deflate, deflate_global, bad,
190			    decomp, error, __LINE__,
191			    zbuf.state->dummy, zbuf.total_out);
192			goto bad;
193		}
194	}
195
196	result = count = zbuf.total_out;
197
198	*out = malloc(result, M_CRYPTO_DATA, M_NOWAIT);
199	if (*out == NULL) {
200		SDT_PROBE3(opencrypto, deflate, deflate_global, bad,
201		    decomp, 0, __LINE__);
202		goto bad;
203	}
204	if (decomp)
205		inflateEnd(&zbuf);
206	else
207		deflateEnd(&zbuf);
208	output = *out;
209	for (bufp = bufh; bufp != NULL; ) {
210		if (count > bufp->size) {
211			struct deflate_buf *p;
212
213			bcopy(bufp->data, *out, bufp->size);
214			*out += bufp->size;
215			count -= bufp->size;
216			p = bufp;
217			bufp = bufp->next;
218			free(p, M_CRYPTO_DATA);
219		} else {
220			/* It should be the last buffer. */
221			bcopy(bufp->data, *out, count);
222			*out += count;
223			free(bufp, M_CRYPTO_DATA);
224			bufp = NULL;
225			count = 0;
226		}
227	}
228	*out = output;
229	SDT_PROBE2(opencrypto, deflate, deflate_global, return, decomp, result);
230	return result;
231
232bad:
233	if (decomp)
234		inflateEnd(&zbuf);
235	else
236		deflateEnd(&zbuf);
237	for (bufp = bufh; bufp != NULL; ) {
238		struct deflate_buf *p;
239
240		p = bufp;
241		bufp = bufp->next;
242		free(p, M_CRYPTO_DATA);
243	}
244bad2:
245	*out = NULL;
246	return 0;
247}
248
249void *
250z_alloc(nil, type, size)
251	void *nil;
252	u_int type, size;
253{
254	void *ptr;
255
256	ptr = malloc(type *size, M_CRYPTO_DATA, M_NOWAIT);
257	return ptr;
258}
259
260void
261z_free(nil, ptr)
262	void *nil, *ptr;
263{
264	free(ptr, M_CRYPTO_DATA);
265}
266