1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Cryptographic API.
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Cipher operations.
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
81da177e4SLinus Torvalds * 2002 Adam J. Richter <adam@yggdrasil.com>
91da177e4SLinus Torvalds * 2004 Jean-Luc Cooke <jlcooke@certainkey.com>
101da177e4SLinus Torvalds */
1142c271c6SHerbert Xu
1242c271c6SHerbert Xu #include <crypto/scatterwalk.h>
131da177e4SLinus Torvalds #include <linux/kernel.h>
141da177e4SLinus Torvalds #include <linux/mm.h>
155c64097aSHerbert Xu #include <linux/module.h>
165c64097aSHerbert Xu #include <linux/scatterlist.h>
175c64097aSHerbert Xu
memcpy_dir(void * buf,void * sgdata,size_t nbytes,int out)185c64097aSHerbert Xu static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
191da177e4SLinus Torvalds {
205c64097aSHerbert Xu void *src = out ? buf : sgdata;
215c64097aSHerbert Xu void *dst = out ? sgdata : buf;
225c64097aSHerbert Xu
235c64097aSHerbert Xu memcpy(dst, src, nbytes);
241da177e4SLinus Torvalds }
251da177e4SLinus Torvalds
scatterwalk_copychunks(void * buf,struct scatter_walk * walk,size_t nbytes,int out)265c64097aSHerbert Xu void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
271da177e4SLinus Torvalds size_t nbytes, int out)
281da177e4SLinus Torvalds {
295c64097aSHerbert Xu for (;;) {
305c64097aSHerbert Xu unsigned int len_this_page = scatterwalk_pagelen(walk);
315c64097aSHerbert Xu u8 *vaddr;
321da177e4SLinus Torvalds
335c64097aSHerbert Xu if (len_this_page > nbytes)
345c64097aSHerbert Xu len_this_page = nbytes;
355c64097aSHerbert Xu
3685eccddeSHerbert Xu if (out != 2) {
37f0dfc0b0SCong Wang vaddr = scatterwalk_map(walk);
385c64097aSHerbert Xu memcpy_dir(buf, vaddr, len_this_page, out);
39f0dfc0b0SCong Wang scatterwalk_unmap(vaddr);
4085eccddeSHerbert Xu }
415c64097aSHerbert Xu
424ee531a3SHerbert Xu scatterwalk_advance(walk, len_this_page);
43f70ee5ecSJ. Bruce Fields
445c64097aSHerbert Xu if (nbytes == len_this_page)
455c64097aSHerbert Xu break;
465c64097aSHerbert Xu
475c64097aSHerbert Xu buf += len_this_page;
485c64097aSHerbert Xu nbytes -= len_this_page;
495c64097aSHerbert Xu
5085eccddeSHerbert Xu scatterwalk_pagedone(walk, out & 1, 1);
51c774e93eSHerbert Xu }
521da177e4SLinus Torvalds }
535c64097aSHerbert Xu EXPORT_SYMBOL_GPL(scatterwalk_copychunks);
545fa0fea2SHerbert Xu
scatterwalk_map_and_copy(void * buf,struct scatterlist * sg,unsigned int start,unsigned int nbytes,int out)555fa0fea2SHerbert Xu void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
565fa0fea2SHerbert Xu unsigned int start, unsigned int nbytes, int out)
575fa0fea2SHerbert Xu {
585fa0fea2SHerbert Xu struct scatter_walk walk;
5974412fd5SHerbert Xu struct scatterlist tmp[2];
605fa0fea2SHerbert Xu
616e050778SHerbert Xu if (!nbytes)
626e050778SHerbert Xu return;
636e050778SHerbert Xu
6474412fd5SHerbert Xu sg = scatterwalk_ffwd(tmp, sg, start);
6574412fd5SHerbert Xu
665fa0fea2SHerbert Xu scatterwalk_start(&walk, sg);
675fa0fea2SHerbert Xu scatterwalk_copychunks(buf, &walk, nbytes, out);
685fa0fea2SHerbert Xu scatterwalk_done(&walk, out, 0);
695fa0fea2SHerbert Xu }
705fa0fea2SHerbert Xu EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy);
71257aff51SJoel Fernandes
scatterwalk_ffwd(struct scatterlist dst[2],struct scatterlist * src,unsigned int len)72fc42bcbaSHerbert Xu struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2],
73fc42bcbaSHerbert Xu struct scatterlist *src,
74fc42bcbaSHerbert Xu unsigned int len)
75fc42bcbaSHerbert Xu {
76fc42bcbaSHerbert Xu for (;;) {
77fc42bcbaSHerbert Xu if (!len)
78fc42bcbaSHerbert Xu return src;
79fc42bcbaSHerbert Xu
80fc42bcbaSHerbert Xu if (src->length > len)
81fc42bcbaSHerbert Xu break;
82fc42bcbaSHerbert Xu
83fc42bcbaSHerbert Xu len -= src->length;
84fc42bcbaSHerbert Xu src = sg_next(src);
85fc42bcbaSHerbert Xu }
86fc42bcbaSHerbert Xu
87fdaef75fSHerbert Xu sg_init_table(dst, 2);
88fc42bcbaSHerbert Xu sg_set_page(dst, sg_page(src), src->length - len, src->offset + len);
898c30fbe6SEric Biggers scatterwalk_crypto_chain(dst, sg_next(src), 2);
90fc42bcbaSHerbert Xu
91fc42bcbaSHerbert Xu return dst;
92fc42bcbaSHerbert Xu }
93fc42bcbaSHerbert Xu EXPORT_SYMBOL_GPL(scatterwalk_ffwd);
94