1 2#include <linux/init.h> 3#include <linux/module.h> 4#include <linux/crypto.h> 5#include <linux/zlib.h> 6#include <linux/vmalloc.h> 7#include <linux/interrupt.h> 8#include <linux/mm.h> 9#include <linux/net.h> 10#include <linux/slab.h> 11 12#define DEFLATE_DEF_LEVEL Z_DEFAULT_COMPRESSION 13#define DEFLATE_DEF_WINBITS 11 14#define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL 15 16struct deflate_ctx { 17 struct z_stream_s comp_stream; 18 struct z_stream_s decomp_stream; 19}; 20 21static int deflate_comp_init(struct deflate_ctx *ctx) 22{ 23 int ret = 0; 24 struct z_stream_s *stream = &ctx->comp_stream; 25 26 stream->workspace = vmalloc(zlib_deflate_workspacesize()); 27 if (!stream->workspace) { 28 ret = -ENOMEM; 29 goto out; 30 } 31 memset(stream->workspace, 0, zlib_deflate_workspacesize()); 32 ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED, 33 -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL, 34 Z_DEFAULT_STRATEGY); 35 if (ret != Z_OK) { 36 ret = -EINVAL; 37 goto out_free; 38 } 39out: 40 return ret; 41out_free: 42 vfree(stream->workspace); 43 goto out; 44} 45 46static int deflate_decomp_init(struct deflate_ctx *ctx) 47{ 48 int ret = 0; 49 struct z_stream_s *stream = &ctx->decomp_stream; 50 51 stream->workspace = kzalloc(zlib_inflate_workspacesize(), GFP_KERNEL); 52 if (!stream->workspace) { 53 ret = -ENOMEM; 54 goto out; 55 } 56 ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS); 57 if (ret != Z_OK) { 58 ret = -EINVAL; 59 goto out_free; 60 } 61out: 62 return ret; 63out_free: 64 kfree(stream->workspace); 65 goto out; 66} 67 68static void deflate_comp_exit(struct deflate_ctx *ctx) 69{ 70 zlib_deflateEnd(&ctx->comp_stream); 71 vfree(ctx->comp_stream.workspace); 72} 73 74static void deflate_decomp_exit(struct deflate_ctx *ctx) 75{ 76 zlib_inflateEnd(&ctx->decomp_stream); 77 kfree(ctx->decomp_stream.workspace); 78} 79 80static int deflate_init(struct crypto_tfm *tfm) 81{ 82 struct deflate_ctx *ctx = crypto_tfm_ctx(tfm); 83 int ret; 84 85 ret = deflate_comp_init(ctx); 86 if (ret) 87 goto out; 88 ret = deflate_decomp_init(ctx); 89 if (ret) 90 deflate_comp_exit(ctx); 91out: 92 return ret; 93} 94 95static void deflate_exit(struct crypto_tfm *tfm) 96{ 97 struct deflate_ctx *ctx = crypto_tfm_ctx(tfm); 98 99 deflate_comp_exit(ctx); 100 deflate_decomp_exit(ctx); 101} 102 103static int deflate_compress(struct crypto_tfm *tfm, const u8 *src, 104 unsigned int slen, u8 *dst, unsigned int *dlen) 105{ 106 int ret = 0; 107 struct deflate_ctx *dctx = crypto_tfm_ctx(tfm); 108 struct z_stream_s *stream = &dctx->comp_stream; 109 110 ret = zlib_deflateReset(stream); 111 if (ret != Z_OK) { 112 ret = -EINVAL; 113 goto out; 114 } 115 116 stream->next_in = (u8 *)src; 117 stream->avail_in = slen; 118 stream->next_out = (u8 *)dst; 119 stream->avail_out = *dlen; 120 121 ret = zlib_deflate(stream, Z_FINISH); 122 if (ret != Z_STREAM_END) { 123 ret = -EINVAL; 124 goto out; 125 } 126 ret = 0; 127 *dlen = stream->total_out; 128out: 129 return ret; 130} 131 132static int deflate_decompress(struct crypto_tfm *tfm, const u8 *src, 133 unsigned int slen, u8 *dst, unsigned int *dlen) 134{ 135 136 int ret = 0; 137 struct deflate_ctx *dctx = crypto_tfm_ctx(tfm); 138 struct z_stream_s *stream = &dctx->decomp_stream; 139 140 ret = zlib_inflateReset(stream); 141 if (ret != Z_OK) { 142 ret = -EINVAL; 143 goto out; 144 } 145 146 stream->next_in = (u8 *)src; 147 stream->avail_in = slen; 148 stream->next_out = (u8 *)dst; 149 stream->avail_out = *dlen; 150 151 ret = zlib_inflate(stream, Z_SYNC_FLUSH); 152 if (ret == Z_OK && !stream->avail_in && stream->avail_out) { 153 u8 zerostuff = 0; 154 stream->next_in = &zerostuff; 155 stream->avail_in = 1; 156 ret = zlib_inflate(stream, Z_FINISH); 157 } 158 if (ret != Z_STREAM_END) { 159 ret = -EINVAL; 160 goto out; 161 } 162 ret = 0; 163 *dlen = stream->total_out; 164out: 165 return ret; 166} 167 168static struct crypto_alg alg = { 169 .cra_name = "deflate", 170 .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, 171 .cra_ctxsize = sizeof(struct deflate_ctx), 172 .cra_module = THIS_MODULE, 173 .cra_list = LIST_HEAD_INIT(alg.cra_list), 174 .cra_init = deflate_init, 175 .cra_exit = deflate_exit, 176 .cra_u = { .compress = { 177 .coa_compress = deflate_compress, 178 .coa_decompress = deflate_decompress } } 179}; 180 181static int __init deflate_mod_init(void) 182{ 183 return crypto_register_alg(&alg); 184} 185 186static void __exit deflate_mod_fini(void) 187{ 188 crypto_unregister_alg(&alg); 189} 190 191module_init(deflate_mod_init); 192module_exit(deflate_mod_fini); 193 194MODULE_LICENSE("GPL"); 195MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP"); 196MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); 197