xref: /linux/crypto/scatterwalk.c (revision fc4bd01d9ff592f620c499686245c093440db0e8)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Cryptographic API.
4  *
5  * Cipher operations.
6  *
7  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
8  *               2002 Adam J. Richter <adam@yggdrasil.com>
9  *               2004 Jean-Luc Cooke <jlcooke@certainkey.com>
10  */
11 
12 #include <crypto/scatterwalk.h>
13 #include <linux/kernel.h>
14 #include <linux/mm.h>
15 #include <linux/module.h>
16 #include <linux/scatterlist.h>
17 
18 void scatterwalk_skip(struct scatter_walk *walk, unsigned int nbytes)
19 {
20 	struct scatterlist *sg = walk->sg;
21 
22 	nbytes += walk->offset - sg->offset;
23 
24 	while (nbytes > sg->length) {
25 		nbytes -= sg->length;
26 		sg = sg_next(sg);
27 	}
28 	walk->sg = sg;
29 	walk->offset = sg->offset + nbytes;
30 }
31 EXPORT_SYMBOL_GPL(scatterwalk_skip);
32 
33 inline void memcpy_from_scatterwalk(void *buf, struct scatter_walk *walk,
34 				    unsigned int nbytes)
35 {
36 	do {
37 		const void *src_addr;
38 		unsigned int to_copy;
39 
40 		src_addr = scatterwalk_next(walk, nbytes, &to_copy);
41 		memcpy(buf, src_addr, to_copy);
42 		scatterwalk_done_src(walk, src_addr, to_copy);
43 		buf += to_copy;
44 		nbytes -= to_copy;
45 	} while (nbytes);
46 }
47 EXPORT_SYMBOL_GPL(memcpy_from_scatterwalk);
48 
49 inline void memcpy_to_scatterwalk(struct scatter_walk *walk, const void *buf,
50 				  unsigned int nbytes)
51 {
52 	do {
53 		void *dst_addr;
54 		unsigned int to_copy;
55 
56 		dst_addr = scatterwalk_next(walk, nbytes, &to_copy);
57 		memcpy(dst_addr, buf, to_copy);
58 		scatterwalk_done_dst(walk, dst_addr, to_copy);
59 		buf += to_copy;
60 		nbytes -= to_copy;
61 	} while (nbytes);
62 }
63 EXPORT_SYMBOL_GPL(memcpy_to_scatterwalk);
64 
65 void memcpy_from_sglist(void *buf, struct scatterlist *sg,
66 			unsigned int start, unsigned int nbytes)
67 {
68 	struct scatter_walk walk;
69 
70 	if (unlikely(nbytes == 0)) /* in case sg == NULL */
71 		return;
72 
73 	scatterwalk_start_at_pos(&walk, sg, start);
74 	memcpy_from_scatterwalk(buf, &walk, nbytes);
75 }
76 EXPORT_SYMBOL_GPL(memcpy_from_sglist);
77 
78 void memcpy_to_sglist(struct scatterlist *sg, unsigned int start,
79 		      const void *buf, unsigned int nbytes)
80 {
81 	struct scatter_walk walk;
82 
83 	if (unlikely(nbytes == 0)) /* in case sg == NULL */
84 		return;
85 
86 	scatterwalk_start_at_pos(&walk, sg, start);
87 	memcpy_to_scatterwalk(&walk, buf, nbytes);
88 }
89 EXPORT_SYMBOL_GPL(memcpy_to_sglist);
90 
91 struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2],
92 				     struct scatterlist *src,
93 				     unsigned int len)
94 {
95 	for (;;) {
96 		if (!len)
97 			return src;
98 
99 		if (src->length > len)
100 			break;
101 
102 		len -= src->length;
103 		src = sg_next(src);
104 	}
105 
106 	sg_init_table(dst, 2);
107 	sg_set_page(dst, sg_page(src), src->length - len, src->offset + len);
108 	scatterwalk_crypto_chain(dst, sg_next(src), 2);
109 
110 	return dst;
111 }
112 EXPORT_SYMBOL_GPL(scatterwalk_ffwd);
113