summaryrefslogtreecommitdiffstats
path: root/crypto/deflate.c
diff options
context:
space:
mode:
authorSalah Triki <salah.triki@gmail.com>2026-09-17 14:00:52 +0100
committerJonathan Cameron <jonathan.cameron@oss.qualcomm.com>2026-09-30 18:59:55 +0100
commite8dd273d199f5bbe295a8e3d8b777c5505b6b2e1 (patch)
tree767c7e109d3e6b9ec6549e99dfec9085d01318ad /crypto/deflate.c
downloadlinux-stable-e8dd273d199f5bbe295a8e3d8b777c5505b6b2e1.tar.gz
linux-stable-e8dd273d199f5bbe295a8e3d8b777c5505b6b2e1.zip
iio: proximity: isl29501: Fix return type of isl29501_register_writegrafted
isl29501_register_write() was returning a u32 instead of an int. Since the function returns negative error codes (such as -ERANGE or return values from i2c_smbus_write_byte_data()), returning an unsigned integer type prevents callers from correctly checking for negative error conditions. Fix this by changing the function return type from u32 to int. This was found through manual code review. Fixes: 1c28799257bc ("iio: light: isl29501: Add support for the ISL29501 ToF sensor.") Signed-off-by: Salah Triki <salah.triki@gmail.com> Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com> Cc: stable@vger.kernel.org Signed-off-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Diffstat (limited to 'crypto/deflate.c')
-rw-r--r--crypto/deflate.c264
1 files changed, 264 insertions, 0 deletions
diff --git a/crypto/deflate.c b/crypto/deflate.c
new file mode 100644
index 000000000..710ebba7c
--- /dev/null
+++ b/crypto/deflate.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * 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>
+ * Copyright (c) 2023 Google, LLC. <ardb@kernel.org>
+ * Copyright (c) 2025 Herbert Xu <herbert@gondor.apana.org.au>
+ */
+#include <crypto/internal/acompress.h>
+#include <crypto/scatterwalk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/overflow.h>
+#include <linux/percpu.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/zlib.h>
+
+#define DEFLATE_DEF_LEVEL Z_DEFAULT_COMPRESSION
+#define DEFLATE_DEF_WINBITS 11
+#define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL
+
+struct deflate_stream {
+ struct z_stream_s stream;
+ u8 workspace[];
+};
+
+static DEFINE_MUTEX(deflate_stream_lock);
+
+static void *deflate_alloc_stream(void)
+{
+ size_t size = max(zlib_inflate_workspacesize(),
+ zlib_deflate_workspacesize(-DEFLATE_DEF_WINBITS,
+ DEFLATE_DEF_MEMLEVEL));
+ struct deflate_stream *ctx;
+
+ ctx = kvmalloc_flex(*ctx, workspace, size);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ctx->stream.workspace = ctx->workspace;
+
+ return ctx;
+}
+
+static void deflate_free_stream(void *ctx)
+{
+ kvfree(ctx);
+}
+
+static struct crypto_acomp_streams deflate_streams = {
+ .alloc_ctx = deflate_alloc_stream,
+ .free_ctx = deflate_free_stream,
+};
+
+static int deflate_compress_one(struct acomp_req *req,
+ struct deflate_stream *ds)
+{
+ struct z_stream_s *stream = &ds->stream;
+ struct acomp_walk walk;
+ int ret;
+
+ ret = acomp_walk_virt(&walk, req, true);
+ if (ret)
+ return ret;
+
+ do {
+ unsigned int dcur;
+
+ dcur = acomp_walk_next_dst(&walk);
+ if (!dcur)
+ return -ENOSPC;
+
+ stream->avail_out = dcur;
+ stream->next_out = walk.dst.virt.addr;
+
+ do {
+ int flush = Z_FINISH;
+ unsigned int scur;
+
+ stream->avail_in = 0;
+ stream->next_in = NULL;
+
+ scur = acomp_walk_next_src(&walk);
+ if (scur) {
+ if (acomp_walk_more_src(&walk, scur))
+ flush = Z_NO_FLUSH;
+ stream->avail_in = scur;
+ stream->next_in = walk.src.virt.addr;
+ }
+
+ ret = zlib_deflate(stream, flush);
+
+ if (scur) {
+ scur -= stream->avail_in;
+ acomp_walk_done_src(&walk, scur);
+ }
+ } while (ret == Z_OK && stream->avail_out);
+
+ acomp_walk_done_dst(&walk, dcur);
+ } while (ret == Z_OK);
+
+ if (ret != Z_STREAM_END)
+ return -EINVAL;
+
+ req->dlen = stream->total_out;
+ return 0;
+}
+
+static int deflate_compress(struct acomp_req *req)
+{
+ struct crypto_acomp_stream *s;
+ struct deflate_stream *ds;
+ int err;
+
+ s = crypto_acomp_lock_stream_bh(&deflate_streams);
+ ds = s->ctx;
+
+ err = zlib_deflateInit2(&ds->stream, DEFLATE_DEF_LEVEL, Z_DEFLATED,
+ -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL,
+ Z_DEFAULT_STRATEGY);
+ if (err != Z_OK) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = deflate_compress_one(req, ds);
+
+out:
+ crypto_acomp_unlock_stream_bh(s);
+
+ return err;
+}
+
+static int deflate_decompress_one(struct acomp_req *req,
+ struct deflate_stream *ds)
+{
+ struct z_stream_s *stream = &ds->stream;
+ bool out_of_space = false;
+ struct acomp_walk walk;
+ int ret;
+
+ ret = acomp_walk_virt(&walk, req, true);
+ if (ret)
+ return ret;
+
+ do {
+ unsigned int scur;
+
+ stream->avail_in = 0;
+ stream->next_in = NULL;
+
+ scur = acomp_walk_next_src(&walk);
+ if (scur) {
+ stream->avail_in = scur;
+ stream->next_in = walk.src.virt.addr;
+ }
+
+ do {
+ unsigned int dcur;
+ unsigned long avail_in;
+
+ dcur = acomp_walk_next_dst(&walk);
+
+ stream->avail_out = dcur;
+ stream->next_out = walk.dst.virt.addr;
+ avail_in = stream->avail_in;
+
+ ret = zlib_inflate(stream, Z_NO_FLUSH);
+
+ if (!dcur && avail_in == stream->avail_in) {
+ out_of_space = true;
+ break;
+ }
+
+ dcur -= stream->avail_out;
+ acomp_walk_done_dst(&walk, dcur);
+ } while (ret == Z_OK && stream->avail_in);
+
+ if (scur)
+ acomp_walk_done_src(&walk, scur);
+
+ if (out_of_space)
+ return -ENOSPC;
+ } while (ret == Z_OK);
+
+ if (ret != Z_STREAM_END)
+ return -EINVAL;
+
+ req->dlen = stream->total_out;
+ return 0;
+}
+
+static int deflate_decompress(struct acomp_req *req)
+{
+ struct crypto_acomp_stream *s;
+ struct deflate_stream *ds;
+ int err;
+
+ s = crypto_acomp_lock_stream_bh(&deflate_streams);
+ ds = s->ctx;
+
+ err = zlib_inflateInit2(&ds->stream, -DEFLATE_DEF_WINBITS);
+ if (err != Z_OK) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = deflate_decompress_one(req, ds);
+
+out:
+ crypto_acomp_unlock_stream_bh(s);
+
+ return err;
+}
+
+static int deflate_init(struct crypto_acomp *tfm)
+{
+ int ret;
+
+ mutex_lock(&deflate_stream_lock);
+ ret = crypto_acomp_alloc_streams(&deflate_streams);
+ mutex_unlock(&deflate_stream_lock);
+
+ return ret;
+}
+
+static struct acomp_alg acomp = {
+ .compress = deflate_compress,
+ .decompress = deflate_decompress,
+ .init = deflate_init,
+ .base.cra_name = "deflate",
+ .base.cra_driver_name = "deflate-generic",
+ .base.cra_flags = CRYPTO_ALG_REQ_VIRT,
+ .base.cra_module = THIS_MODULE,
+};
+
+static int __init deflate_mod_init(void)
+{
+ return crypto_register_acomp(&acomp);
+}
+
+static void __exit deflate_mod_fini(void)
+{
+ crypto_unregister_acomp(&acomp);
+ crypto_acomp_free_streams(&deflate_streams);
+}
+
+module_init(deflate_mod_init);
+module_exit(deflate_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP");
+MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
+MODULE_AUTHOR("Ard Biesheuvel <ardb@kernel.org>");
+MODULE_AUTHOR("Herbert Xu <herbert@gondor.apana.org.au>");
+MODULE_ALIAS_CRYPTO("deflate");
+MODULE_ALIAS_CRYPTO("deflate-generic");