xref: /linux/crypto/scatterwalk.c (revision 2874c5fd)
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