162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Cryptographic API. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Cipher operations. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 862306a36Sopenharmony_ci * 2002 Adam J. Richter <adam@yggdrasil.com> 962306a36Sopenharmony_ci * 2004 Jean-Luc Cooke <jlcooke@certainkey.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/mm.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/scatterlist.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci void *src = out ? buf : sgdata; 2162306a36Sopenharmony_ci void *dst = out ? sgdata : buf; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci memcpy(dst, src, nbytes); 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_civoid scatterwalk_copychunks(void *buf, struct scatter_walk *walk, 2762306a36Sopenharmony_ci size_t nbytes, int out) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci for (;;) { 3062306a36Sopenharmony_ci unsigned int len_this_page = scatterwalk_pagelen(walk); 3162306a36Sopenharmony_ci u8 *vaddr; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (len_this_page > nbytes) 3462306a36Sopenharmony_ci len_this_page = nbytes; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (out != 2) { 3762306a36Sopenharmony_ci vaddr = scatterwalk_map(walk); 3862306a36Sopenharmony_ci memcpy_dir(buf, vaddr, len_this_page, out); 3962306a36Sopenharmony_ci scatterwalk_unmap(vaddr); 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci scatterwalk_advance(walk, len_this_page); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (nbytes == len_this_page) 4562306a36Sopenharmony_ci break; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci buf += len_this_page; 4862306a36Sopenharmony_ci nbytes -= len_this_page; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci scatterwalk_pagedone(walk, out & 1, 1); 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(scatterwalk_copychunks); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_civoid scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, 5662306a36Sopenharmony_ci unsigned int start, unsigned int nbytes, int out) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct scatter_walk walk; 5962306a36Sopenharmony_ci struct scatterlist tmp[2]; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (!nbytes) 6262306a36Sopenharmony_ci return; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci sg = scatterwalk_ffwd(tmp, sg, start); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci scatterwalk_start(&walk, sg); 6762306a36Sopenharmony_ci scatterwalk_copychunks(buf, &walk, nbytes, out); 6862306a36Sopenharmony_ci scatterwalk_done(&walk, out, 0); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(scatterwalk_map_and_copy); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2], 7362306a36Sopenharmony_ci struct scatterlist *src, 7462306a36Sopenharmony_ci unsigned int len) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci for (;;) { 7762306a36Sopenharmony_ci if (!len) 7862306a36Sopenharmony_ci return src; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (src->length > len) 8162306a36Sopenharmony_ci break; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci len -= src->length; 8462306a36Sopenharmony_ci src = sg_next(src); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci sg_init_table(dst, 2); 8862306a36Sopenharmony_ci sg_set_page(dst, sg_page(src), src->length - len, src->offset + len); 8962306a36Sopenharmony_ci scatterwalk_crypto_chain(dst, sg_next(src), 2); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return dst; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(scatterwalk_ffwd); 94