sfc: Detach net device when stopping queues for reconfiguration
[linux-2.6.git] / crypto / zlib.c
1 /*
2  * Cryptographic API.
3  *
4  * Zlib algorithm
5  *
6  * Copyright 2008 Sony Corporation
7  *
8  * Based on deflate.c, which is
9  * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
10  *
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)
14  * any later version.
15  *
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.
21  */
22
23 #define pr_fmt(fmt)     "%s: " fmt, __func__
24
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>
30 #include <linux/mm.h>
31 #include <linux/net.h>
32
33 #include <crypto/internal/compress.h>
34
35 #include <net/netlink.h>
36
37
38 struct zlib_ctx {
39         struct z_stream_s comp_stream;
40         struct z_stream_s decomp_stream;
41         int decomp_windowBits;
42 };
43
44
45 static void zlib_comp_exit(struct zlib_ctx *ctx)
46 {
47         struct z_stream_s *stream = &ctx->comp_stream;
48
49         if (stream->workspace) {
50                 zlib_deflateEnd(stream);
51                 vfree(stream->workspace);
52                 stream->workspace = NULL;
53         }
54 }
55
56 static void zlib_decomp_exit(struct zlib_ctx *ctx)
57 {
58         struct z_stream_s *stream = &ctx->decomp_stream;
59
60         if (stream->workspace) {
61                 zlib_inflateEnd(stream);
62                 vfree(stream->workspace);
63                 stream->workspace = NULL;
64         }
65 }
66
67 static int zlib_init(struct crypto_tfm *tfm)
68 {
69         return 0;
70 }
71
72 static void zlib_exit(struct crypto_tfm *tfm)
73 {
74         struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
75
76         zlib_comp_exit(ctx);
77         zlib_decomp_exit(ctx);
78 }
79
80
81 static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
82                                unsigned int len)
83 {
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;
88         size_t workspacesize;
89         int ret;
90
91         ret = nla_parse(tb, ZLIB_COMP_MAX, params, len, NULL);
92         if (ret)
93                 return ret;
94
95         zlib_comp_exit(ctx);
96
97         window_bits = tb[ZLIB_COMP_WINDOWBITS]
98                                         ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
99                                         : MAX_WBITS;
100         mem_level = tb[ZLIB_COMP_MEMLEVEL]
101                                         ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
102                                         : DEF_MEM_LEVEL;
103
104         workspacesize = zlib_deflate_workspacesize(window_bits, mem_level);
105         stream->workspace = vzalloc(workspacesize);
106         if (!stream->workspace)
107                 return -ENOMEM;
108
109         ret = zlib_deflateInit2(stream,
110                                 tb[ZLIB_COMP_LEVEL]
111                                         ? nla_get_u32(tb[ZLIB_COMP_LEVEL])
112                                         : Z_DEFAULT_COMPRESSION,
113                                 tb[ZLIB_COMP_METHOD]
114                                         ? nla_get_u32(tb[ZLIB_COMP_METHOD])
115                                         : Z_DEFLATED,
116                                 window_bits,
117                                 mem_level,
118                                 tb[ZLIB_COMP_STRATEGY]
119                                         ? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
120                                         : Z_DEFAULT_STRATEGY);
121         if (ret != Z_OK) {
122                 vfree(stream->workspace);
123                 stream->workspace = NULL;
124                 return -EINVAL;
125         }
126
127         return 0;
128 }
129
130 static int zlib_compress_init(struct crypto_pcomp *tfm)
131 {
132         int ret;
133         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
134         struct z_stream_s *stream = &dctx->comp_stream;
135
136         ret = zlib_deflateReset(stream);
137         if (ret != Z_OK)
138                 return -EINVAL;
139
140         return 0;
141 }
142
143 static int zlib_compress_update(struct crypto_pcomp *tfm,
144                                 struct comp_request *req)
145 {
146         int ret;
147         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
148         struct z_stream_s *stream = &dctx->comp_stream;
149
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;
155
156         ret = zlib_deflate(stream, Z_NO_FLUSH);
157         switch (ret) {
158         case Z_OK:
159                 break;
160
161         case Z_BUF_ERROR:
162                 pr_debug("zlib_deflate could not make progress\n");
163                 return -EAGAIN;
164
165         default:
166                 pr_debug("zlib_deflate failed %d\n", ret);
167                 return -EINVAL;
168         }
169
170         ret = req->avail_out - stream->avail_out;
171         pr_debug("avail_in %u, avail_out %u (consumed %u, 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;
178         return ret;
179 }
180
181 static int zlib_compress_final(struct crypto_pcomp *tfm,
182                                struct comp_request *req)
183 {
184         int ret;
185         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
186         struct z_stream_s *stream = &dctx->comp_stream;
187
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;
193
194         ret = zlib_deflate(stream, Z_FINISH);
195         if (ret != Z_STREAM_END) {
196                 pr_debug("zlib_deflate failed %d\n", ret);
197                 return -EINVAL;
198         }
199
200         ret = req->avail_out - stream->avail_out;
201         pr_debug("avail_in %u, avail_out %u (consumed %u, 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;
208         return ret;
209 }
210
211
212 static int zlib_decompress_setup(struct crypto_pcomp *tfm, void *params,
213                                  unsigned int len)
214 {
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];
218         int ret = 0;
219
220         ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL);
221         if (ret)
222                 return ret;
223
224         zlib_decomp_exit(ctx);
225
226         ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS]
227                                  ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
228                                  : DEF_WBITS;
229
230         stream->workspace = vzalloc(zlib_inflate_workspacesize());
231         if (!stream->workspace)
232                 return -ENOMEM;
233
234         ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
235         if (ret != Z_OK) {
236                 vfree(stream->workspace);
237                 stream->workspace = NULL;
238                 return -EINVAL;
239         }
240
241         return 0;
242 }
243
244 static int zlib_decompress_init(struct crypto_pcomp *tfm)
245 {
246         int ret;
247         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
248         struct z_stream_s *stream = &dctx->decomp_stream;
249
250         ret = zlib_inflateReset(stream);
251         if (ret != Z_OK)
252                 return -EINVAL;
253
254         return 0;
255 }
256
257 static int zlib_decompress_update(struct crypto_pcomp *tfm,
258                                   struct comp_request *req)
259 {
260         int ret;
261         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
262         struct z_stream_s *stream = &dctx->decomp_stream;
263
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;
269
270         ret = zlib_inflate(stream, Z_SYNC_FLUSH);
271         switch (ret) {
272         case Z_OK:
273         case Z_STREAM_END:
274                 break;
275
276         case Z_BUF_ERROR:
277                 pr_debug("zlib_inflate could not make progress\n");
278                 return -EAGAIN;
279
280         default:
281                 pr_debug("zlib_inflate failed %d\n", ret);
282                 return -EINVAL;
283         }
284
285         ret = req->avail_out - stream->avail_out;
286         pr_debug("avail_in %u, avail_out %u (consumed %u, 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;
293         return ret;
294 }
295
296 static int zlib_decompress_final(struct crypto_pcomp *tfm,
297                                  struct comp_request *req)
298 {
299         int ret;
300         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
301         struct z_stream_s *stream = &dctx->decomp_stream;
302
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;
308
309         if (dctx->decomp_windowBits < 0) {
310                 ret = zlib_inflate(stream, Z_SYNC_FLUSH);
311                 /*
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).
315                  */
316                 if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
317                         const void *saved_next_in = stream->next_in;
318                         u8 zerostuff = 0;
319
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;
325                 }
326         } else
327                 ret = zlib_inflate(stream, Z_FINISH);
328         if (ret != Z_STREAM_END) {
329                 pr_debug("zlib_inflate failed %d\n", ret);
330                 return -EINVAL;
331         }
332
333         ret = req->avail_out - stream->avail_out;
334         pr_debug("avail_in %u, avail_out %u (consumed %u, 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;
341         return ret;
342 }
343
344
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,
354
355         .base                   = {
356                 .cra_name       = "zlib",
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,
362         }
363 };
364
365 static int __init zlib_mod_init(void)
366 {
367         return crypto_register_pcomp(&zlib_alg);
368 }
369
370 static void __exit zlib_mod_fini(void)
371 {
372         crypto_unregister_pcomp(&zlib_alg);
373 }
374
375 module_init(zlib_mod_init);
376 module_exit(zlib_mod_fini);
377
378 MODULE_LICENSE("GPL");
379 MODULE_DESCRIPTION("Zlib Compression Algorithm");
380 MODULE_AUTHOR("Sony Corporation");