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 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 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 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 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 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 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