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>
32 #include <linux/slab.h>
34 #include <crypto/internal/compress.h>
36 #include <net/netlink.h>
40 struct z_stream_s comp_stream
;
41 struct z_stream_s decomp_stream
;
42 int decomp_windowBits
;
46 static void zlib_comp_exit(struct zlib_ctx
*ctx
)
48 struct z_stream_s
*stream
= &ctx
->comp_stream
;
50 if (stream
->workspace
) {
51 zlib_deflateEnd(stream
);
52 vfree(stream
->workspace
);
53 stream
->workspace
= NULL
;
57 static void zlib_decomp_exit(struct zlib_ctx
*ctx
)
59 struct z_stream_s
*stream
= &ctx
->decomp_stream
;
61 if (stream
->workspace
) {
62 zlib_inflateEnd(stream
);
63 kfree(stream
->workspace
);
64 stream
->workspace
= NULL
;
68 static int zlib_init(struct crypto_tfm
*tfm
)
73 static void zlib_exit(struct crypto_tfm
*tfm
)
75 struct zlib_ctx
*ctx
= crypto_tfm_ctx(tfm
);
78 zlib_decomp_exit(ctx
);
82 static int zlib_compress_setup(struct crypto_pcomp
*tfm
, void *params
,
85 struct zlib_ctx
*ctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
86 struct z_stream_s
*stream
= &ctx
->comp_stream
;
87 struct nlattr
*tb
[ZLIB_COMP_MAX
+ 1];
88 int window_bits
, mem_level
;
92 ret
= nla_parse(tb
, ZLIB_COMP_MAX
, params
, len
, NULL
);
98 window_bits
= tb
[ZLIB_COMP_WINDOWBITS
]
99 ? nla_get_u32(tb
[ZLIB_COMP_WINDOWBITS
])
101 mem_level
= tb
[ZLIB_COMP_MEMLEVEL
]
102 ? nla_get_u32(tb
[ZLIB_COMP_MEMLEVEL
])
105 workspacesize
= zlib_deflate_workspacesize(window_bits
, mem_level
);
106 stream
->workspace
= vzalloc(workspacesize
);
107 if (!stream
->workspace
)
110 ret
= zlib_deflateInit2(stream
,
112 ? nla_get_u32(tb
[ZLIB_COMP_LEVEL
])
113 : Z_DEFAULT_COMPRESSION
,
115 ? nla_get_u32(tb
[ZLIB_COMP_METHOD
])
119 tb
[ZLIB_COMP_STRATEGY
]
120 ? nla_get_u32(tb
[ZLIB_COMP_STRATEGY
])
121 : Z_DEFAULT_STRATEGY
);
123 vfree(stream
->workspace
);
124 stream
->workspace
= NULL
;
131 static int zlib_compress_init(struct crypto_pcomp
*tfm
)
134 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
135 struct z_stream_s
*stream
= &dctx
->comp_stream
;
137 ret
= zlib_deflateReset(stream
);
144 static int zlib_compress_update(struct crypto_pcomp
*tfm
,
145 struct comp_request
*req
)
148 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
149 struct z_stream_s
*stream
= &dctx
->comp_stream
;
151 pr_debug("avail_in %u, avail_out %u\n", req
->avail_in
, req
->avail_out
);
152 stream
->next_in
= req
->next_in
;
153 stream
->avail_in
= req
->avail_in
;
154 stream
->next_out
= req
->next_out
;
155 stream
->avail_out
= req
->avail_out
;
157 ret
= zlib_deflate(stream
, Z_NO_FLUSH
);
163 pr_debug("zlib_deflate could not make progress\n");
167 pr_debug("zlib_deflate failed %d\n", ret
);
171 ret
= req
->avail_out
- stream
->avail_out
;
172 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
173 stream
->avail_in
, stream
->avail_out
,
174 req
->avail_in
- stream
->avail_in
, ret
);
175 req
->next_in
= stream
->next_in
;
176 req
->avail_in
= stream
->avail_in
;
177 req
->next_out
= stream
->next_out
;
178 req
->avail_out
= stream
->avail_out
;
182 static int zlib_compress_final(struct crypto_pcomp
*tfm
,
183 struct comp_request
*req
)
186 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
187 struct z_stream_s
*stream
= &dctx
->comp_stream
;
189 pr_debug("avail_in %u, avail_out %u\n", req
->avail_in
, req
->avail_out
);
190 stream
->next_in
= req
->next_in
;
191 stream
->avail_in
= req
->avail_in
;
192 stream
->next_out
= req
->next_out
;
193 stream
->avail_out
= req
->avail_out
;
195 ret
= zlib_deflate(stream
, Z_FINISH
);
196 if (ret
!= Z_STREAM_END
) {
197 pr_debug("zlib_deflate failed %d\n", ret
);
201 ret
= req
->avail_out
- stream
->avail_out
;
202 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
203 stream
->avail_in
, stream
->avail_out
,
204 req
->avail_in
- stream
->avail_in
, ret
);
205 req
->next_in
= stream
->next_in
;
206 req
->avail_in
= stream
->avail_in
;
207 req
->next_out
= stream
->next_out
;
208 req
->avail_out
= stream
->avail_out
;
213 static int zlib_decompress_setup(struct crypto_pcomp
*tfm
, void *params
,
216 struct zlib_ctx
*ctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
217 struct z_stream_s
*stream
= &ctx
->decomp_stream
;
218 struct nlattr
*tb
[ZLIB_DECOMP_MAX
+ 1];
221 ret
= nla_parse(tb
, ZLIB_DECOMP_MAX
, params
, len
, NULL
);
225 zlib_decomp_exit(ctx
);
227 ctx
->decomp_windowBits
= tb
[ZLIB_DECOMP_WINDOWBITS
]
228 ? nla_get_u32(tb
[ZLIB_DECOMP_WINDOWBITS
])
231 stream
->workspace
= kzalloc(zlib_inflate_workspacesize(), GFP_KERNEL
);
232 if (!stream
->workspace
)
235 ret
= zlib_inflateInit2(stream
, ctx
->decomp_windowBits
);
237 kfree(stream
->workspace
);
238 stream
->workspace
= NULL
;
245 static int zlib_decompress_init(struct crypto_pcomp
*tfm
)
248 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
249 struct z_stream_s
*stream
= &dctx
->decomp_stream
;
251 ret
= zlib_inflateReset(stream
);
258 static int zlib_decompress_update(struct crypto_pcomp
*tfm
,
259 struct comp_request
*req
)
262 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
263 struct z_stream_s
*stream
= &dctx
->decomp_stream
;
265 pr_debug("avail_in %u, avail_out %u\n", req
->avail_in
, req
->avail_out
);
266 stream
->next_in
= req
->next_in
;
267 stream
->avail_in
= req
->avail_in
;
268 stream
->next_out
= req
->next_out
;
269 stream
->avail_out
= req
->avail_out
;
271 ret
= zlib_inflate(stream
, Z_SYNC_FLUSH
);
278 pr_debug("zlib_inflate could not make progress\n");
282 pr_debug("zlib_inflate failed %d\n", ret
);
286 ret
= req
->avail_out
- stream
->avail_out
;
287 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
288 stream
->avail_in
, stream
->avail_out
,
289 req
->avail_in
- stream
->avail_in
, ret
);
290 req
->next_in
= stream
->next_in
;
291 req
->avail_in
= stream
->avail_in
;
292 req
->next_out
= stream
->next_out
;
293 req
->avail_out
= stream
->avail_out
;
297 static int zlib_decompress_final(struct crypto_pcomp
*tfm
,
298 struct comp_request
*req
)
301 struct zlib_ctx
*dctx
= crypto_tfm_ctx(crypto_pcomp_tfm(tfm
));
302 struct z_stream_s
*stream
= &dctx
->decomp_stream
;
304 pr_debug("avail_in %u, avail_out %u\n", req
->avail_in
, req
->avail_out
);
305 stream
->next_in
= req
->next_in
;
306 stream
->avail_in
= req
->avail_in
;
307 stream
->next_out
= req
->next_out
;
308 stream
->avail_out
= req
->avail_out
;
310 if (dctx
->decomp_windowBits
< 0) {
311 ret
= zlib_inflate(stream
, Z_SYNC_FLUSH
);
313 * Work around a bug in zlib, which sometimes wants to taste an
314 * extra byte when being used in the (undocumented) raw deflate
315 * mode. (From USAGI).
317 if (ret
== Z_OK
&& !stream
->avail_in
&& stream
->avail_out
) {
318 const void *saved_next_in
= stream
->next_in
;
321 stream
->next_in
= &zerostuff
;
322 stream
->avail_in
= 1;
323 ret
= zlib_inflate(stream
, Z_FINISH
);
324 stream
->next_in
= saved_next_in
;
325 stream
->avail_in
= 0;
328 ret
= zlib_inflate(stream
, Z_FINISH
);
329 if (ret
!= Z_STREAM_END
) {
330 pr_debug("zlib_inflate failed %d\n", ret
);
334 ret
= req
->avail_out
- stream
->avail_out
;
335 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
336 stream
->avail_in
, stream
->avail_out
,
337 req
->avail_in
- stream
->avail_in
, ret
);
338 req
->next_in
= stream
->next_in
;
339 req
->avail_in
= stream
->avail_in
;
340 req
->next_out
= stream
->next_out
;
341 req
->avail_out
= stream
->avail_out
;
346 static struct pcomp_alg zlib_alg
= {
347 .compress_setup
= zlib_compress_setup
,
348 .compress_init
= zlib_compress_init
,
349 .compress_update
= zlib_compress_update
,
350 .compress_final
= zlib_compress_final
,
351 .decompress_setup
= zlib_decompress_setup
,
352 .decompress_init
= zlib_decompress_init
,
353 .decompress_update
= zlib_decompress_update
,
354 .decompress_final
= zlib_decompress_final
,
358 .cra_flags
= CRYPTO_ALG_TYPE_PCOMPRESS
,
359 .cra_ctxsize
= sizeof(struct zlib_ctx
),
360 .cra_module
= THIS_MODULE
,
361 .cra_init
= zlib_init
,
362 .cra_exit
= zlib_exit
,
366 static int __init
zlib_mod_init(void)
368 return crypto_register_pcomp(&zlib_alg
);
371 static void __exit
zlib_mod_fini(void)
373 crypto_unregister_pcomp(&zlib_alg
);
376 module_init(zlib_mod_init
);
377 module_exit(zlib_mod_fini
);
379 MODULE_LICENSE("GPL");
380 MODULE_DESCRIPTION("Zlib Compression Algorithm");
381 MODULE_AUTHOR("Sony Corporation");