Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Cryptographic API.
0004  *
0005  * Cipher operations.
0006  *
0007  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
0008  *               2002 Adam J. Richter <adam@yggdrasil.com>
0009  *               2004 Jean-Luc Cooke <jlcooke@certainkey.com>
0010  */
0011 
0012 #include <crypto/scatterwalk.h>
0013 #include <linux/kernel.h>
0014 #include <linux/mm.h>
0015 #include <linux/module.h>
0016 #include <linux/scatterlist.h>
0017 
0018 static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
0019 {
0020     void *src = out ? buf : sgdata;
0021     void *dst = out ? sgdata : buf;
0022 
0023     memcpy(dst, src, nbytes);
0024 }
0025 
0026 void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
0027                 size_t nbytes, int out)
0028 {
0029     for (;;) {
0030         unsigned int len_this_page = scatterwalk_pagelen(walk);
0031         u8 *vaddr;
0032 
0033         if (len_this_page > nbytes)
0034             len_this_page = nbytes;
0035 
0036         if (out != 2) {
0037             vaddr = scatterwalk_map(walk);
0038             memcpy_dir(buf, vaddr, len_this_page, out);
0039             scatterwalk_unmap(vaddr);
0040         }
0041 
0042         scatterwalk_advance(walk, len_this_page);
0043 
0044         if (nbytes == len_this_page)
0045             break;
0046 
0047         buf += len_this_page;
0048         nbytes -= len_this_page;
0049 
0050         scatterwalk_pagedone(walk, out & 1, 1);
0051     }
0052 }
0053 EXPORT_SYMBOL_GPL(scatterwalk_copychunks);
0054 
0055 void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
0056                   unsigned int start, unsigned int nbytes, int out)
0057 {
0058     struct scatter_walk walk;
0059     struct scatterlist tmp[2];
0060 
0061     if (!nbytes)
0062         return;
0063 
0064     sg = scatterwalk_ffwd(tmp, sg, start);
0065 
0066     scatterwalk_start(&walk, sg);
0067     scatterwalk_copychunks(buf, &walk, nbytes, out);
0068     scatterwalk_done(&walk, out, 0);
0069 }
0070 EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy);
0071 
0072 struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2],
0073                      struct scatterlist *src,
0074                      unsigned int len)
0075 {
0076     for (;;) {
0077         if (!len)
0078             return src;
0079 
0080         if (src->length > len)
0081             break;
0082 
0083         len -= src->length;
0084         src = sg_next(src);
0085     }
0086 
0087     sg_init_table(dst, 2);
0088     sg_set_page(dst, sg_page(src), src->length - len, src->offset + len);
0089     scatterwalk_crypto_chain(dst, sg_next(src), 2);
0090 
0091     return dst;
0092 }
0093 EXPORT_SYMBOL_GPL(scatterwalk_ffwd);