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