xref: /freebsd/sys/opencrypto/cryptodeflate.c (revision 7ef62cebc2f965b0f640263e179276928885e33d)
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/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/malloc.h>
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/sdt.h>
44 #include <sys/systm.h>
45 #include <contrib/zlib/zlib.h>
46 
47 #include <opencrypto/cryptodev.h>
48 #include <opencrypto/deflate.h>
49 
50 SDT_PROVIDER_DECLARE(opencrypto);
51 SDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, entry,
52     "int", "uint32_t");
53 SDT_PROBE_DEFINE6(opencrypto, deflate, deflate_global, bad,
54     "int", "int", "int", "int", "int", "int");
55 SDT_PROBE_DEFINE6(opencrypto, deflate, deflate_global, iter,
56     "int", "int", "int", "int", "int", "int");
57 SDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, return,
58     "int", "uint32_t");
59 
60 int window_inflate = -1 * MAX_WBITS;
61 int window_deflate = -12;
62 
63 static void *
64 crypto_zalloc(void *nil, u_int type, u_int size)
65 {
66 	void *ptr;
67 
68 	ptr = malloc(type *size, M_CRYPTO_DATA, M_NOWAIT);
69 	return ptr;
70 }
71 
72 static void
73 crypto_zfree(void *nil, void *ptr)
74 {
75 
76 	free(ptr, M_CRYPTO_DATA);
77 }
78 
79 /*
80  * This function takes a block of data and (de)compress it using the deflate
81  * algorithm
82  */
83 
84 uint32_t
85 deflate_global(uint8_t *data, uint32_t size, int decomp, uint8_t **out)
86 {
87 	/* decomp indicates whether we compress (0) or decompress (1) */
88 
89 	z_stream zbuf;
90 	uint8_t *output;
91 	uint32_t count, result;
92 	int error, i;
93 	struct deflate_buf *bufh, *bufp;
94 
95 	SDT_PROBE2(opencrypto, deflate, deflate_global, entry, decomp, size);
96 
97 	bufh = bufp = NULL;
98 	if (!decomp) {
99 		i = 1;
100 	} else {
101 		/*
102 	 	 * Choose a buffer with 4x the size of the input buffer
103 	 	 * for the size of the output buffer in the case of
104 	 	 * decompression. If it's not sufficient, it will need to be
105 	 	 * updated while the decompression is going on.
106 	 	 */
107 		i = 4;
108 	}
109 	/*
110 	 * Make sure we do have enough output space.  Repeated calls to
111 	 * deflate need at least 6 bytes of output buffer space to avoid
112 	 * repeated markers.  We will always provide at least 16 bytes.
113 	 */
114 	while ((size * i) < 16)
115 		i++;
116 
117 	bufh = bufp = malloc(sizeof(*bufp) + (size_t)(size * i),
118 	    M_CRYPTO_DATA, M_NOWAIT);
119 	if (bufp == NULL) {
120 		SDT_PROBE6(opencrypto, deflate, deflate_global, bad,
121 		    decomp, 0, __LINE__, 0, 0, 0);
122 		goto bad2;
123 	}
124 	bufp->next = NULL;
125 	bufp->size = size * i;
126 
127 	bzero(&zbuf, sizeof(z_stream));
128 	zbuf.zalloc = crypto_zalloc;
129 	zbuf.zfree = crypto_zfree;
130 	zbuf.opaque = Z_NULL;
131 	zbuf.next_in = data;	/* Data that is going to be processed. */
132 	zbuf.avail_in = size;	/* Total length of data to be processed. */
133 	zbuf.next_out = bufp->data;
134 	zbuf.avail_out = bufp->size;
135 
136 	error = decomp ? inflateInit2(&zbuf, window_inflate) :
137 	    deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD,
138 		    window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY);
139 	if (error != Z_OK) {
140 		SDT_PROBE6(opencrypto, deflate, deflate_global, bad,
141 		    decomp, error, __LINE__, 0, 0, 0);
142 		goto bad;
143 	}
144 
145 	for (;;) {
146 		error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) :
147 				 deflate(&zbuf, Z_FINISH);
148 		if (error != Z_OK && error != Z_STREAM_END) {
149 			SDT_PROBE6(opencrypto, deflate, deflate_global, bad,
150 			    decomp, error, __LINE__,
151 			    zbuf.avail_in, zbuf.avail_out, zbuf.total_out);
152 			goto bad;
153 		}
154 		SDT_PROBE6(opencrypto, deflate, deflate_global, iter,
155 		    decomp, error, __LINE__,
156 		    zbuf.avail_in, zbuf.avail_out, 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_PROBE6(opencrypto, deflate, deflate_global,
171 				    bad, decomp, 0, __LINE__, 0, 0, 0);
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 			SDT_PROBE6(opencrypto, deflate, deflate_global,
183 			    bad, decomp, error, __LINE__,
184 			    zbuf.avail_in, zbuf.avail_out, zbuf.total_out);
185 			goto bad;
186 		}
187 	}
188 
189 	result = count = zbuf.total_out;
190 
191 	*out = malloc(result, M_CRYPTO_DATA, M_NOWAIT);
192 	if (*out == NULL) {
193 		SDT_PROBE6(opencrypto, deflate, deflate_global, bad,
194 		    decomp, 0, __LINE__, 0, 0, 0);
195 		goto bad;
196 	}
197 	if (decomp)
198 		inflateEnd(&zbuf);
199 	else
200 		deflateEnd(&zbuf);
201 	output = *out;
202 	for (bufp = bufh; bufp != NULL; ) {
203 		if (count > bufp->size) {
204 			struct deflate_buf *p;
205 
206 			bcopy(bufp->data, *out, bufp->size);
207 			*out += bufp->size;
208 			count -= bufp->size;
209 			p = bufp;
210 			bufp = bufp->next;
211 			free(p, M_CRYPTO_DATA);
212 		} else {
213 			/* It should be the last buffer. */
214 			bcopy(bufp->data, *out, count);
215 			*out += count;
216 			free(bufp, M_CRYPTO_DATA);
217 			bufp = NULL;
218 			count = 0;
219 		}
220 	}
221 	*out = output;
222 	SDT_PROBE2(opencrypto, deflate, deflate_global, return, decomp, result);
223 	return result;
224 
225 bad:
226 	if (decomp)
227 		inflateEnd(&zbuf);
228 	else
229 		deflateEnd(&zbuf);
230 	for (bufp = bufh; bufp != NULL; ) {
231 		struct deflate_buf *p;
232 
233 		p = bufp;
234 		bufp = bufp->next;
235 		free(p, M_CRYPTO_DATA);
236 	}
237 bad2:
238 	*out = NULL;
239 	return 0;
240 }
241