Back to home page

LXR

 
 

    


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