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
scatterwalk_skip(struct scatter_walk * walk,unsigned int nbytes)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
memcpy_from_scatterwalk(void * buf,struct scatter_walk * walk,unsigned int nbytes)33 inline void memcpy_from_scatterwalk(void *buf, struct scatter_walk *walk,
34 unsigned int nbytes)
35 {
36 do {
37 unsigned int to_copy;
38
39 to_copy = scatterwalk_next(walk, nbytes);
40 memcpy(buf, walk->addr, to_copy);
41 scatterwalk_done_src(walk, to_copy);
42 buf += to_copy;
43 nbytes -= to_copy;
44 } while (nbytes);
45 }
46 EXPORT_SYMBOL_GPL(memcpy_from_scatterwalk);
47
memcpy_to_scatterwalk(struct scatter_walk * walk,const void * buf,unsigned int nbytes)48 inline void memcpy_to_scatterwalk(struct scatter_walk *walk, const void *buf,
49 unsigned int nbytes)
50 {
51 do {
52 unsigned int to_copy;
53
54 to_copy = scatterwalk_next(walk, nbytes);
55 memcpy(walk->addr, buf, to_copy);
56 scatterwalk_done_dst(walk, to_copy);
57 buf += to_copy;
58 nbytes -= to_copy;
59 } while (nbytes);
60 }
61 EXPORT_SYMBOL_GPL(memcpy_to_scatterwalk);
62
memcpy_from_sglist(void * buf,struct scatterlist * sg,unsigned int start,unsigned int nbytes)63 void memcpy_from_sglist(void *buf, struct scatterlist *sg,
64 unsigned int start, unsigned int nbytes)
65 {
66 struct scatter_walk walk;
67
68 if (unlikely(nbytes == 0)) /* in case sg == NULL */
69 return;
70
71 scatterwalk_start_at_pos(&walk, sg, start);
72 memcpy_from_scatterwalk(buf, &walk, nbytes);
73 }
74 EXPORT_SYMBOL_GPL(memcpy_from_sglist);
75
memcpy_to_sglist(struct scatterlist * sg,unsigned int start,const void * buf,unsigned int nbytes)76 void memcpy_to_sglist(struct scatterlist *sg, unsigned int start,
77 const void *buf, unsigned int nbytes)
78 {
79 struct scatter_walk walk;
80
81 if (unlikely(nbytes == 0)) /* in case sg == NULL */
82 return;
83
84 scatterwalk_start_at_pos(&walk, sg, start);
85 memcpy_to_scatterwalk(&walk, buf, nbytes);
86 }
87 EXPORT_SYMBOL_GPL(memcpy_to_sglist);
88
memcpy_sglist(struct scatterlist * dst,struct scatterlist * src,unsigned int nbytes)89 void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src,
90 unsigned int nbytes)
91 {
92 struct scatter_walk swalk;
93 struct scatter_walk dwalk;
94
95 if (unlikely(nbytes == 0)) /* in case sg == NULL */
96 return;
97
98 scatterwalk_start(&swalk, src);
99 scatterwalk_start(&dwalk, dst);
100
101 do {
102 unsigned int slen, dlen;
103 unsigned int len;
104
105 slen = scatterwalk_next(&swalk, nbytes);
106 dlen = scatterwalk_next(&dwalk, nbytes);
107 len = min(slen, dlen);
108 memcpy(dwalk.addr, swalk.addr, len);
109 scatterwalk_done_dst(&dwalk, len);
110 scatterwalk_done_src(&swalk, len);
111 nbytes -= len;
112 } while (nbytes);
113 }
114 EXPORT_SYMBOL_GPL(memcpy_sglist);
115
scatterwalk_ffwd(struct scatterlist dst[2],struct scatterlist * src,unsigned int len)116 struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2],
117 struct scatterlist *src,
118 unsigned int len)
119 {
120 for (;;) {
121 if (!len)
122 return src;
123
124 if (src->length > len)
125 break;
126
127 len -= src->length;
128 src = sg_next(src);
129 }
130
131 sg_init_table(dst, 2);
132 sg_set_page(dst, sg_page(src), src->length - len, src->offset + len);
133 scatterwalk_crypto_chain(dst, sg_next(src), 2);
134
135 return dst;
136 }
137 EXPORT_SYMBOL_GPL(scatterwalk_ffwd);
138