RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / crypto / zlib.c
blobd0f0e53ce657939cdf7d77537494245db80c2d91
3 #define pr_fmt(fmt) "%s: " fmt, __func__
5 #include <linux/init.h>
6 #include <linux/module.h>
7 #include <linux/zlib.h>
8 #include <linux/vmalloc.h>
9 #include <linux/interrupt.h>
10 #include <linux/mm.h>
11 #include <linux/net.h>
12 #include <linux/slab.h>
14 #include <crypto/internal/compress.h>
16 #include <net/netlink.h>
19 struct zlib_ctx {
20 struct z_stream_s comp_stream;
21 struct z_stream_s decomp_stream;
22 int decomp_windowBits;
26 static void zlib_comp_exit(struct zlib_ctx *ctx)
28 struct z_stream_s *stream = &ctx->comp_stream;
30 if (stream->workspace) {
31 zlib_deflateEnd(stream);
32 vfree(stream->workspace);
33 stream->workspace = NULL;
37 static void zlib_decomp_exit(struct zlib_ctx *ctx)
39 struct z_stream_s *stream = &ctx->decomp_stream;
41 if (stream->workspace) {
42 zlib_inflateEnd(stream);
43 kfree(stream->workspace);
44 stream->workspace = NULL;
48 static int zlib_init(struct crypto_tfm *tfm)
50 return 0;
53 static void zlib_exit(struct crypto_tfm *tfm)
55 struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
57 zlib_comp_exit(ctx);
58 zlib_decomp_exit(ctx);
62 static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
63 unsigned int len)
65 struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
66 struct z_stream_s *stream = &ctx->comp_stream;
67 struct nlattr *tb[ZLIB_COMP_MAX + 1];
68 size_t workspacesize;
69 int ret;
71 ret = nla_parse(tb, ZLIB_COMP_MAX, params, len, NULL);
72 if (ret)
73 return ret;
75 zlib_comp_exit(ctx);
77 workspacesize = zlib_deflate_workspacesize();
78 stream->workspace = vmalloc(workspacesize);
79 if (!stream->workspace)
80 return -ENOMEM;
82 memset(stream->workspace, 0, workspacesize);
83 ret = zlib_deflateInit2(stream,
84 tb[ZLIB_COMP_LEVEL]
85 ? nla_get_u32(tb[ZLIB_COMP_LEVEL])
86 : Z_DEFAULT_COMPRESSION,
87 tb[ZLIB_COMP_METHOD]
88 ? nla_get_u32(tb[ZLIB_COMP_METHOD])
89 : Z_DEFLATED,
90 tb[ZLIB_COMP_WINDOWBITS]
91 ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
92 : MAX_WBITS,
93 tb[ZLIB_COMP_MEMLEVEL]
94 ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
95 : DEF_MEM_LEVEL,
96 tb[ZLIB_COMP_STRATEGY]
97 ? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
98 : Z_DEFAULT_STRATEGY);
99 if (ret != Z_OK) {
100 vfree(stream->workspace);
101 stream->workspace = NULL;
102 return -EINVAL;
105 return 0;
108 static int zlib_compress_init(struct crypto_pcomp *tfm)
110 int ret;
111 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
112 struct z_stream_s *stream = &dctx->comp_stream;
114 ret = zlib_deflateReset(stream);
115 if (ret != Z_OK)
116 return -EINVAL;
118 return 0;
121 static int zlib_compress_update(struct crypto_pcomp *tfm,
122 struct comp_request *req)
124 int ret;
125 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
126 struct z_stream_s *stream = &dctx->comp_stream;
128 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
129 stream->next_in = req->next_in;
130 stream->avail_in = req->avail_in;
131 stream->next_out = req->next_out;
132 stream->avail_out = req->avail_out;
134 ret = zlib_deflate(stream, Z_NO_FLUSH);
135 switch (ret) {
136 case Z_OK:
137 break;
139 case Z_BUF_ERROR:
140 pr_debug("zlib_deflate could not make progress\n");
141 return -EAGAIN;
143 default:
144 pr_debug("zlib_deflate failed %d\n", ret);
145 return -EINVAL;
148 ret = req->avail_out - stream->avail_out;
149 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
150 stream->avail_in, stream->avail_out,
151 req->avail_in - stream->avail_in, ret);
152 req->next_in = stream->next_in;
153 req->avail_in = stream->avail_in;
154 req->next_out = stream->next_out;
155 req->avail_out = stream->avail_out;
156 return ret;
159 static int zlib_compress_final(struct crypto_pcomp *tfm,
160 struct comp_request *req)
162 int ret;
163 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
164 struct z_stream_s *stream = &dctx->comp_stream;
166 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
167 stream->next_in = req->next_in;
168 stream->avail_in = req->avail_in;
169 stream->next_out = req->next_out;
170 stream->avail_out = req->avail_out;
172 ret = zlib_deflate(stream, Z_FINISH);
173 if (ret != Z_STREAM_END) {
174 pr_debug("zlib_deflate failed %d\n", ret);
175 return -EINVAL;
178 ret = req->avail_out - stream->avail_out;
179 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
180 stream->avail_in, stream->avail_out,
181 req->avail_in - stream->avail_in, ret);
182 req->next_in = stream->next_in;
183 req->avail_in = stream->avail_in;
184 req->next_out = stream->next_out;
185 req->avail_out = stream->avail_out;
186 return ret;
190 static int zlib_decompress_setup(struct crypto_pcomp *tfm, void *params,
191 unsigned int len)
193 struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
194 struct z_stream_s *stream = &ctx->decomp_stream;
195 struct nlattr *tb[ZLIB_DECOMP_MAX + 1];
196 int ret = 0;
198 ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL);
199 if (ret)
200 return ret;
202 zlib_decomp_exit(ctx);
204 ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS]
205 ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
206 : DEF_WBITS;
208 stream->workspace = kzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
209 if (!stream->workspace)
210 return -ENOMEM;
212 ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
213 if (ret != Z_OK) {
214 kfree(stream->workspace);
215 stream->workspace = NULL;
216 return -EINVAL;
219 return 0;
222 static int zlib_decompress_init(struct crypto_pcomp *tfm)
224 int ret;
225 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
226 struct z_stream_s *stream = &dctx->decomp_stream;
228 ret = zlib_inflateReset(stream);
229 if (ret != Z_OK)
230 return -EINVAL;
232 return 0;
235 static int zlib_decompress_update(struct crypto_pcomp *tfm,
236 struct comp_request *req)
238 int ret;
239 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
240 struct z_stream_s *stream = &dctx->decomp_stream;
242 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
243 stream->next_in = req->next_in;
244 stream->avail_in = req->avail_in;
245 stream->next_out = req->next_out;
246 stream->avail_out = req->avail_out;
248 ret = zlib_inflate(stream, Z_SYNC_FLUSH);
249 switch (ret) {
250 case Z_OK:
251 case Z_STREAM_END:
252 break;
254 case Z_BUF_ERROR:
255 pr_debug("zlib_inflate could not make progress\n");
256 return -EAGAIN;
258 default:
259 pr_debug("zlib_inflate failed %d\n", ret);
260 return -EINVAL;
263 ret = req->avail_out - stream->avail_out;
264 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
265 stream->avail_in, stream->avail_out,
266 req->avail_in - stream->avail_in, ret);
267 req->next_in = stream->next_in;
268 req->avail_in = stream->avail_in;
269 req->next_out = stream->next_out;
270 req->avail_out = stream->avail_out;
271 return ret;
274 static int zlib_decompress_final(struct crypto_pcomp *tfm,
275 struct comp_request *req)
277 int ret;
278 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
279 struct z_stream_s *stream = &dctx->decomp_stream;
281 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
282 stream->next_in = req->next_in;
283 stream->avail_in = req->avail_in;
284 stream->next_out = req->next_out;
285 stream->avail_out = req->avail_out;
287 if (dctx->decomp_windowBits < 0) {
288 ret = zlib_inflate(stream, Z_SYNC_FLUSH);
289 if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
290 const void *saved_next_in = stream->next_in;
291 u8 zerostuff = 0;
293 stream->next_in = &zerostuff;
294 stream->avail_in = 1;
295 ret = zlib_inflate(stream, Z_FINISH);
296 stream->next_in = saved_next_in;
297 stream->avail_in = 0;
299 } else
300 ret = zlib_inflate(stream, Z_FINISH);
301 if (ret != Z_STREAM_END) {
302 pr_debug("zlib_inflate failed %d\n", ret);
303 return -EINVAL;
306 ret = req->avail_out - stream->avail_out;
307 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
308 stream->avail_in, stream->avail_out,
309 req->avail_in - stream->avail_in, ret);
310 req->next_in = stream->next_in;
311 req->avail_in = stream->avail_in;
312 req->next_out = stream->next_out;
313 req->avail_out = stream->avail_out;
314 return ret;
318 static struct pcomp_alg zlib_alg = {
319 .compress_setup = zlib_compress_setup,
320 .compress_init = zlib_compress_init,
321 .compress_update = zlib_compress_update,
322 .compress_final = zlib_compress_final,
323 .decompress_setup = zlib_decompress_setup,
324 .decompress_init = zlib_decompress_init,
325 .decompress_update = zlib_decompress_update,
326 .decompress_final = zlib_decompress_final,
328 .base = {
329 .cra_name = "zlib",
330 .cra_flags = CRYPTO_ALG_TYPE_PCOMPRESS,
331 .cra_ctxsize = sizeof(struct zlib_ctx),
332 .cra_module = THIS_MODULE,
333 .cra_init = zlib_init,
334 .cra_exit = zlib_exit,
338 static int __init zlib_mod_init(void)
340 return crypto_register_pcomp(&zlib_alg);
343 static void __exit zlib_mod_fini(void)
345 crypto_unregister_pcomp(&zlib_alg);
348 module_init(zlib_mod_init);
349 module_exit(zlib_mod_fini);
351 MODULE_LICENSE("GPL");
352 MODULE_DESCRIPTION("Zlib Compression Algorithm");
353 MODULE_AUTHOR("Sony Corporation");