6 * Copyright 2008 Sony Corporation
8 * Based on deflate.c, which is
9 * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the Free
13 * Software Foundation; either version 2 of the License, or (at your option)
16 * FIXME: deflate transforms will require up to a total of about 436k of kernel
17 * memory on i386 (390k for compression, the rest for decompression), as the
18 * current zlib kernel code uses a worst case pre-allocation system by default.
19 * This needs to be fixed so that the amount of memory required is properly
20 * related to the winbits and memlevel parameters.
23 #define pr_fmt(fmt) "%s: " fmt, __func__
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/zlib.h>
28 #include <linux/vmalloc.h>
29 #include <linux/interrupt.h>
31 #include <linux/net.h>
33 #include <crypto/internal/compress.h>
35 #include <net/netlink.h>
39 struct z_stream_s comp_stream
;
40 struct z_stream_s decomp_stream
;
41 int decomp_windowBits
;
45 static void zlib_comp_exit(struct zlib_ctx
*ctx
)
47 struct z_stream_s
*stream
= &ctx
->comp_stream
;
49 if (stream
->workspace
) {
50 zlib_deflateEnd(stream
);
51 vfree(stream
->workspace
);
52 stream
->workspace
= NULL
;
56 static void zlib_decomp_exit(struct zlib_ctx
*ctx
)
58 struct z_stream_s
*stream
= &ctx
->decomp_stream
;
60 if (stream
->workspace
) {
61 zlib_inflateEnd(stream
);
62 vfree(stream
->workspace
);
63 stream
->workspace
= NULL
;
67 static int zlib_init(struct crypto_tfm
*tfm
)
72 static void zlib_exit(struct crypto_tfm
*tfm
)
74 struct zlib_ctx
*ctx
= crypto_tfm_ctx(tfm
);
77 zlib_decomp_exit(ctx
);
81 static int zlib_compress_setup(struct crypto_pcomp
*tfm
, void *params
,
84 struct zlib_ctx
*ctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
85 struct z_stream_s
*stream
= &ctx
->comp_stream
;
86 struct nlattr
*tb
[ZLIB_COMP_MAX
+ 1];
87 int window_bits
, mem_level
;
91 ret
= nla_parse(tb
, ZLIB_COMP_MAX
, params
, len
, NULL
);
97 window_bits
= tb
[ZLIB_COMP_WINDOWBITS
]
98 ? nla_get_u32(tb
[ZLIB_COMP_WINDOWBITS
])
100 mem_level
= tb
[ZLIB_COMP_MEMLEVEL
]
101 ? nla_get_u32(tb
[ZLIB_COMP_MEMLEVEL
])
104 workspacesize
= zlib_deflate_workspacesize(window_bits
, mem_level
);
105 stream
->workspace
= vzalloc(workspacesize
);
106 if (!stream
->workspace
)
109 ret
= zlib_deflateInit2(stream
,
111 ? nla_get_u32(tb
[ZLIB_COMP_LEVEL
])
112 : Z_DEFAULT_COMPRESSION
,
114 ? nla_get_u32(tb
[ZLIB_COMP_METHOD
])
118 tb
[ZLIB_COMP_STRATEGY
]
119 ? nla_get_u32(tb
[ZLIB_COMP_STRATEGY
])
120 : Z_DEFAULT_STRATEGY
);
122 vfree(stream
->workspace
);
123 stream
->workspace
= NULL
;
130 static int zlib_compress_init(struct crypto_pcomp
*tfm
)
133 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
134 struct z_stream_s
*stream
= &dctx
->comp_stream
;
136 ret
= zlib_deflateReset(stream
);
143 static int zlib_compress_update(struct crypto_pcomp
*tfm
,
144 struct comp_request
*req
)
147 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
148 struct z_stream_s
*stream
= &dctx
->comp_stream
;
150 pr_debug("avail_in %u, avail_out %u\n", req
->avail_in
, req
->avail_out
);
151 stream
->next_in
= req
->next_in
;
152 stream
->avail_in
= req
->avail_in
;
153 stream
->next_out
= req
->next_out
;
154 stream
->avail_out
= req
->avail_out
;
156 ret
= zlib_deflate(stream
, Z_NO_FLUSH
);
162 pr_debug("zlib_deflate could not make progress\n");
166 pr_debug("zlib_deflate failed %d\n", ret
);
170 ret
= req
->avail_out
- stream
->avail_out
;
171 pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
172 stream
->avail_in
, stream
->avail_out
,
173 req
->avail_in
- stream
->avail_in
, ret
);
174 req
->next_in
= stream
->next_in
;
175 req
->avail_in
= stream
->avail_in
;
176 req
->next_out
= stream
->next_out
;
177 req
->avail_out
= stream
->avail_out
;
181 static int zlib_compress_final(struct crypto_pcomp
*tfm
,
182 struct comp_request
*req
)
185 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
186 struct z_stream_s
*stream
= &dctx
->comp_stream
;
188 pr_debug("avail_in %u, avail_out %u\n", req
->avail_in
, req
->avail_out
);
189 stream
->next_in
= req
->next_in
;
190 stream
->avail_in
= req
->avail_in
;
191 stream
->next_out
= req
->next_out
;
192 stream
->avail_out
= req
->avail_out
;
194 ret
= zlib_deflate(stream
, Z_FINISH
);
195 if (ret
!= Z_STREAM_END
) {
196 pr_debug("zlib_deflate failed %d\n", ret
);
200 ret
= req
->avail_out
- stream
->avail_out
;
201 pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
202 stream
->avail_in
, stream
->avail_out
,
203 req
->avail_in
- stream
->avail_in
, ret
);
204 req
->next_in
= stream
->next_in
;
205 req
->avail_in
= stream
->avail_in
;
206 req
->next_out
= stream
->next_out
;
207 req
->avail_out
= stream
->avail_out
;
212 static int zlib_decompress_setup(struct crypto_pcomp
*tfm
, void *params
,
215 struct zlib_ctx
*ctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
216 struct z_stream_s
*stream
= &ctx
->decomp_stream
;
217 struct nlattr
*tb
[ZLIB_DECOMP_MAX
+ 1];
220 ret
= nla_parse(tb
, ZLIB_DECOMP_MAX
, params
, len
, NULL
);
224 zlib_decomp_exit(ctx
);
226 ctx
->decomp_windowBits
= tb
[ZLIB_DECOMP_WINDOWBITS
]
227 ? nla_get_u32(tb
[ZLIB_DECOMP_WINDOWBITS
])
230 stream
->workspace
= vzalloc(zlib_inflate_workspacesize());
231 if (!stream
->workspace
)
234 ret
= zlib_inflateInit2(stream
, ctx
->decomp_windowBits
);
236 vfree(stream
->workspace
);
237 stream
->workspace
= NULL
;
244 static int zlib_decompress_init(struct crypto_pcomp
*tfm
)
247 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
248 struct z_stream_s
*stream
= &dctx
->decomp_stream
;
250 ret
= zlib_inflateReset(stream
);
257 static int zlib_decompress_update(struct crypto_pcomp
*tfm
,
258 struct comp_request
*req
)
261 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
262 struct z_stream_s
*stream
= &dctx
->decomp_stream
;
264 pr_debug("avail_in %u, avail_out %u\n", req
->avail_in
, req
->avail_out
);
265 stream
->next_in
= req
->next_in
;
266 stream
->avail_in
= req
->avail_in
;
267 stream
->next_out
= req
->next_out
;
268 stream
->avail_out
= req
->avail_out
;
270 ret
= zlib_inflate(stream
, Z_SYNC_FLUSH
);
277 pr_debug("zlib_inflate could not make progress\n");
281 pr_debug("zlib_inflate failed %d\n", ret
);
285 ret
= req
->avail_out
- stream
->avail_out
;
286 pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
287 stream
->avail_in
, stream
->avail_out
,
288 req
->avail_in
- stream
->avail_in
, ret
);
289 req
->next_in
= stream
->next_in
;
290 req
->avail_in
= stream
->avail_in
;
291 req
->next_out
= stream
->next_out
;
292 req
->avail_out
= stream
->avail_out
;
296 static int zlib_decompress_final(struct crypto_pcomp
*tfm
,
297 struct comp_request
*req
)
300 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
301 struct z_stream_s
*stream
= &dctx
->decomp_stream
;
303 pr_debug("avail_in %u, avail_out %u\n", req
->avail_in
, req
->avail_out
);
304 stream
->next_in
= req
->next_in
;
305 stream
->avail_in
= req
->avail_in
;
306 stream
->next_out
= req
->next_out
;
307 stream
->avail_out
= req
->avail_out
;
309 if (dctx
->decomp_windowBits
< 0) {
310 ret
= zlib_inflate(stream
, Z_SYNC_FLUSH
);
312 * Work around a bug in zlib, which sometimes wants to taste an
313 * extra byte when being used in the (undocumented) raw deflate
314 * mode. (From USAGI).
316 if (ret
== Z_OK
&& !stream
->avail_in
&& stream
->avail_out
) {
317 const void *saved_next_in
= stream
->next_in
;
320 stream
->next_in
= &zerostuff
;
321 stream
->avail_in
= 1;
322 ret
= zlib_inflate(stream
, Z_FINISH
);
323 stream
->next_in
= saved_next_in
;
324 stream
->avail_in
= 0;
327 ret
= zlib_inflate(stream
, Z_FINISH
);
328 if (ret
!= Z_STREAM_END
) {
329 pr_debug("zlib_inflate failed %d\n", ret
);
333 ret
= req
->avail_out
- stream
->avail_out
;
334 pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
335 stream
->avail_in
, stream
->avail_out
,
336 req
->avail_in
- stream
->avail_in
, ret
);
337 req
->next_in
= stream
->next_in
;
338 req
->avail_in
= stream
->avail_in
;
339 req
->next_out
= stream
->next_out
;
340 req
->avail_out
= stream
->avail_out
;
345 static struct pcomp_alg zlib_alg
= {
346 .compress_setup
= zlib_compress_setup
,
347 .compress_init
= zlib_compress_init
,
348 .compress_update
= zlib_compress_update
,
349 .compress_final
= zlib_compress_final
,
350 .decompress_setup
= zlib_decompress_setup
,
351 .decompress_init
= zlib_decompress_init
,
352 .decompress_update
= zlib_decompress_update
,
353 .decompress_final
= zlib_decompress_final
,
357 .cra_flags
= CRYPTO_ALG_TYPE_PCOMPRESS
,
358 .cra_ctxsize
= sizeof(struct zlib_ctx
),
359 .cra_module
= THIS_MODULE
,
360 .cra_init
= zlib_init
,
361 .cra_exit
= zlib_exit
,
365 static int __init
zlib_mod_init(void)
367 return crypto_register_pcomp(&zlib_alg
);
370 static void __exit
zlib_mod_fini(void)
372 crypto_unregister_pcomp(&zlib_alg
);
375 module_init(zlib_mod_init
);
376 module_exit(zlib_mod_fini
);
378 MODULE_LICENSE("GPL");
379 MODULE_DESCRIPTION("Zlib Compression Algorithm");
380 MODULE_AUTHOR("Sony Corporation");