Blame view

crypto/deflate.c 5.42 KB
9472d763b   Richard Hartmann   crypto: deflate -...
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
   * Cryptographic API.
   *
   * Deflate algorithm (RFC 1951), implemented here primarily for use
   * by IPCOMP (RFC 3173 & RFC 2394).
   *
   * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
9472d763b   Richard Hartmann   crypto: deflate -...
8
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the Free
9472d763b   Richard Hartmann   crypto: deflate -...
11
   * Software Foundation; either version 2 of the License, or (at your option)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   * any later version.
   *
   * FIXME: deflate transforms will require up to a total of about 436k of kernel
   * memory on i386 (390k for compression, the rest for decompression), as the
   * current zlib kernel code uses a worst case pre-allocation system by default.
   * This needs to be fixed so that the amount of memory required is properly
   * related to the  winbits and memlevel parameters.
   *
   * The default winbits of 11 should suit most packets, and it may be something
   * to configure on a per-tfm basis in the future.
   *
   * Currently, compression history is not maintained between tfm calls, as
   * it is not needed for IPCOMP and keeps the code simpler.  It can be
   * implemented if someone wants it.
   */
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/crypto.h>
  #include <linux/zlib.h>
  #include <linux/vmalloc.h>
  #include <linux/interrupt.h>
  #include <linux/mm.h>
  #include <linux/net.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  
  #define DEFLATE_DEF_LEVEL		Z_DEFAULT_COMPRESSION
  #define DEFLATE_DEF_WINBITS		11
  #define DEFLATE_DEF_MEMLEVEL		MAX_MEM_LEVEL
  
  struct deflate_ctx {
  	struct z_stream_s comp_stream;
  	struct z_stream_s decomp_stream;
  };
  
  static int deflate_comp_init(struct deflate_ctx *ctx)
  {
  	int ret = 0;
  	struct z_stream_s *stream = &ctx->comp_stream;
565d76cb7   Jim Keniston   zlib: slim down z...
49
50
  	stream->workspace = vzalloc(zlib_deflate_workspacesize(
  				-DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL));
9472d763b   Richard Hartmann   crypto: deflate -...
51
  	if (!stream->workspace) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
  		ret = -ENOMEM;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
  	ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED,
  	                        -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL,
  	                        Z_DEFAULT_STRATEGY);
  	if (ret != Z_OK) {
  		ret = -EINVAL;
  		goto out_free;
  	}
9472d763b   Richard Hartmann   crypto: deflate -...
62
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
68
69
70
71
72
  	return ret;
  out_free:
  	vfree(stream->workspace);
  	goto out;
  }
  
  static int deflate_decomp_init(struct deflate_ctx *ctx)
  {
  	int ret = 0;
  	struct z_stream_s *stream = &ctx->decomp_stream;
7ab24bfdf   David S. Miller   net+crypto: Use v...
73
  	stream->workspace = vzalloc(zlib_inflate_workspacesize());
9472d763b   Richard Hartmann   crypto: deflate -...
74
  	if (!stream->workspace) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
  		ret = -ENOMEM;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
81
82
83
84
85
  	ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS);
  	if (ret != Z_OK) {
  		ret = -EINVAL;
  		goto out_free;
  	}
  out:
  	return ret;
  out_free:
7ab24bfdf   David S. Miller   net+crypto: Use v...
86
  	vfree(stream->workspace);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
  	goto out;
  }
  
  static void deflate_comp_exit(struct deflate_ctx *ctx)
  {
9ffb7146f   Artem B. Bityuckiy   [PATCH] crypto: c...
92
  	zlib_deflateEnd(&ctx->comp_stream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
96
97
  	vfree(ctx->comp_stream.workspace);
  }
  
  static void deflate_decomp_exit(struct deflate_ctx *ctx)
  {
9ffb7146f   Artem B. Bityuckiy   [PATCH] crypto: c...
98
  	zlib_inflateEnd(&ctx->decomp_stream);
7ab24bfdf   David S. Miller   net+crypto: Use v...
99
  	vfree(ctx->decomp_stream.workspace);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  }
6c2bb98bc   Herbert Xu   [CRYPTO] all: Pas...
101
  static int deflate_init(struct crypto_tfm *tfm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  {
6c2bb98bc   Herbert Xu   [CRYPTO] all: Pas...
103
  	struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  	int ret;
9472d763b   Richard Hartmann   crypto: deflate -...
105

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
108
109
110
111
112
113
114
  	ret = deflate_comp_init(ctx);
  	if (ret)
  		goto out;
  	ret = deflate_decomp_init(ctx);
  	if (ret)
  		deflate_comp_exit(ctx);
  out:
  	return ret;
  }
6c2bb98bc   Herbert Xu   [CRYPTO] all: Pas...
115
  static void deflate_exit(struct crypto_tfm *tfm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  {
6c2bb98bc   Herbert Xu   [CRYPTO] all: Pas...
117
  	struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
  	deflate_comp_exit(ctx);
  	deflate_decomp_exit(ctx);
  }
6c2bb98bc   Herbert Xu   [CRYPTO] all: Pas...
121
122
  static int deflate_compress(struct crypto_tfm *tfm, const u8 *src,
  			    unsigned int slen, u8 *dst, unsigned int *dlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
  {
  	int ret = 0;
6c2bb98bc   Herbert Xu   [CRYPTO] all: Pas...
125
  	struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  	struct z_stream_s *stream = &dctx->comp_stream;
  
  	ret = zlib_deflateReset(stream);
  	if (ret != Z_OK) {
  		ret = -EINVAL;
  		goto out;
  	}
  
  	stream->next_in = (u8 *)src;
  	stream->avail_in = slen;
  	stream->next_out = (u8 *)dst;
  	stream->avail_out = *dlen;
  
  	ret = zlib_deflate(stream, Z_FINISH);
  	if (ret != Z_STREAM_END) {
  		ret = -EINVAL;
  		goto out;
  	}
  	ret = 0;
  	*dlen = stream->total_out;
  out:
  	return ret;
  }
9472d763b   Richard Hartmann   crypto: deflate -...
149

6c2bb98bc   Herbert Xu   [CRYPTO] all: Pas...
150
151
  static int deflate_decompress(struct crypto_tfm *tfm, const u8 *src,
  			      unsigned int slen, u8 *dst, unsigned int *dlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  {
9472d763b   Richard Hartmann   crypto: deflate -...
153

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  	int ret = 0;
6c2bb98bc   Herbert Xu   [CRYPTO] all: Pas...
155
  	struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  	struct z_stream_s *stream = &dctx->decomp_stream;
  
  	ret = zlib_inflateReset(stream);
  	if (ret != Z_OK) {
  		ret = -EINVAL;
  		goto out;
  	}
  
  	stream->next_in = (u8 *)src;
  	stream->avail_in = slen;
  	stream->next_out = (u8 *)dst;
  	stream->avail_out = *dlen;
  
  	ret = zlib_inflate(stream, Z_SYNC_FLUSH);
  	/*
  	 * Work around a bug in zlib, which sometimes wants to taste an extra
  	 * byte when being used in the (undocumented) raw deflate mode.
  	 * (From USAGI).
  	 */
  	if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
  		u8 zerostuff = 0;
  		stream->next_in = &zerostuff;
9472d763b   Richard Hartmann   crypto: deflate -...
178
  		stream->avail_in = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  		ret = zlib_inflate(stream, Z_FINISH);
  	}
  	if (ret != Z_STREAM_END) {
  		ret = -EINVAL;
  		goto out;
  	}
  	ret = 0;
  	*dlen = stream->total_out;
  out:
  	return ret;
  }
  
  static struct crypto_alg alg = {
  	.cra_name		= "deflate",
  	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
  	.cra_ctxsize		= sizeof(struct deflate_ctx),
  	.cra_module		= THIS_MODULE,
  	.cra_list		= LIST_HEAD_INIT(alg.cra_list),
c7fc05992   Herbert Xu   [CRYPTO] api: Add...
197
198
  	.cra_init		= deflate_init,
  	.cra_exit		= deflate_exit,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
  	.cra_u			= { .compress = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
  	.coa_compress 		= deflate_compress,
  	.coa_decompress  	= deflate_decompress } }
  };
3af5b90bd   Kamalesh Babulal   [CRYPTO] all: Cle...
203
  static int __init deflate_mod_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
  {
  	return crypto_register_alg(&alg);
  }
3af5b90bd   Kamalesh Babulal   [CRYPTO] all: Cle...
207
  static void __exit deflate_mod_fini(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
  {
  	crypto_unregister_alg(&alg);
  }
3af5b90bd   Kamalesh Babulal   [CRYPTO] all: Cle...
211
212
  module_init(deflate_mod_init);
  module_exit(deflate_mod_fini);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP");
  MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");