18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Cryptographic API.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Cipher operations.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
88c2ecf20Sopenharmony_ci *               2002 Adam J. Richter <adam@yggdrasil.com>
98c2ecf20Sopenharmony_ci *               2004 Jean-Luc Cooke <jlcooke@certainkey.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/mm.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	void *src = out ? buf : sgdata;
218c2ecf20Sopenharmony_ci	void *dst = out ? sgdata : buf;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	memcpy(dst, src, nbytes);
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
278c2ecf20Sopenharmony_ci			    size_t nbytes, int out)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	for (;;) {
308c2ecf20Sopenharmony_ci		unsigned int len_this_page = scatterwalk_pagelen(walk);
318c2ecf20Sopenharmony_ci		u8 *vaddr;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci		if (len_this_page > nbytes)
348c2ecf20Sopenharmony_ci			len_this_page = nbytes;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci		if (out != 2) {
378c2ecf20Sopenharmony_ci			vaddr = scatterwalk_map(walk);
388c2ecf20Sopenharmony_ci			memcpy_dir(buf, vaddr, len_this_page, out);
398c2ecf20Sopenharmony_ci			scatterwalk_unmap(vaddr);
408c2ecf20Sopenharmony_ci		}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci		scatterwalk_advance(walk, len_this_page);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci		if (nbytes == len_this_page)
458c2ecf20Sopenharmony_ci			break;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci		buf += len_this_page;
488c2ecf20Sopenharmony_ci		nbytes -= len_this_page;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci		scatterwalk_pagedone(walk, out & 1, 1);
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scatterwalk_copychunks);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_civoid scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
568c2ecf20Sopenharmony_ci			      unsigned int start, unsigned int nbytes, int out)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	struct scatter_walk walk;
598c2ecf20Sopenharmony_ci	struct scatterlist tmp[2];
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	if (!nbytes)
628c2ecf20Sopenharmony_ci		return;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	sg = scatterwalk_ffwd(tmp, sg, start);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	scatterwalk_start(&walk, sg);
678c2ecf20Sopenharmony_ci	scatterwalk_copychunks(buf, &walk, nbytes, out);
688c2ecf20Sopenharmony_ci	scatterwalk_done(&walk, out, 0);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scatterwalk_map_and_copy);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistruct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2],
738c2ecf20Sopenharmony_ci				     struct scatterlist *src,
748c2ecf20Sopenharmony_ci				     unsigned int len)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	for (;;) {
778c2ecf20Sopenharmony_ci		if (!len)
788c2ecf20Sopenharmony_ci			return src;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci		if (src->length > len)
818c2ecf20Sopenharmony_ci			break;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		len -= src->length;
848c2ecf20Sopenharmony_ci		src = sg_next(src);
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	sg_init_table(dst, 2);
888c2ecf20Sopenharmony_ci	sg_set_page(dst, sg_page(src), src->length - len, src->offset + len);
898c2ecf20Sopenharmony_ci	scatterwalk_crypto_chain(dst, sg_next(src), 2);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	return dst;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scatterwalk_ffwd);
94