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