2005-04-17 02:20:36 +04:00
/*
* Cryptographic API .
*
* Cipher operations .
*
* Copyright ( c ) 2002 James Morris < jmorris @ intercode . com . au >
* 2002 Adam J . Richter < adam @ yggdrasil . com >
* 2004 Jean - Luc Cooke < jlcooke @ certainkey . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation ; either version 2 of the License , or ( at your option )
* any later version .
*
*/
2007-12-07 13:52:49 +03:00
# include <crypto/scatterwalk.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/mm.h>
2006-08-12 15:56:17 +04:00
# include <linux/module.h>
# include <linux/scatterlist.h>
static inline void memcpy_dir ( void * buf , void * sgdata , size_t nbytes , int out )
2005-04-17 02:20:36 +04:00
{
2006-08-12 15:56:17 +04:00
void * src = out ? buf : sgdata ;
void * dst = out ? sgdata : buf ;
memcpy ( dst , src , nbytes ) ;
2005-04-17 02:20:36 +04:00
}
2006-08-12 15:56:17 +04:00
void scatterwalk_copychunks ( void * buf , struct scatter_walk * walk ,
size_t nbytes , int out )
2005-04-17 02:20:36 +04:00
{
2006-08-12 15:56:17 +04:00
for ( ; ; ) {
unsigned int len_this_page = scatterwalk_pagelen ( walk ) ;
u8 * vaddr ;
if ( len_this_page > nbytes )
len_this_page = nbytes ;
2016-07-12 08:17:55 +03:00
if ( out ! = 2 ) {
vaddr = scatterwalk_map ( walk ) ;
memcpy_dir ( buf , vaddr , len_this_page , out ) ;
scatterwalk_unmap ( vaddr ) ;
}
2006-08-12 15:56:17 +04:00
2007-03-31 06:16:20 +04:00
scatterwalk_advance ( walk , len_this_page ) ;
2007-03-21 00:50:12 +03:00
2006-08-12 15:56:17 +04:00
if ( nbytes = = len_this_page )
break ;
buf + = len_this_page ;
nbytes - = len_this_page ;
2005-04-17 02:20:36 +04:00
2016-07-12 08:17:55 +03:00
scatterwalk_pagedone ( walk , out & 1 , 1 ) ;
2005-07-07 00:51:31 +04:00
}
2005-04-17 02:20:36 +04:00
}
2006-08-12 15:56:17 +04:00
EXPORT_SYMBOL_GPL ( scatterwalk_copychunks ) ;
2007-08-29 12:31:34 +04:00
void scatterwalk_map_and_copy ( void * buf , struct scatterlist * sg ,
unsigned int start , unsigned int nbytes , int out )
{
struct scatter_walk walk ;
2015-05-21 10:11:12 +03:00
struct scatterlist tmp [ 2 ] ;
2007-08-29 12:31:34 +04:00
2007-12-13 19:44:11 +03:00
if ( ! nbytes )
return ;
2015-05-21 10:11:12 +03:00
sg = scatterwalk_ffwd ( tmp , sg , start ) ;
2007-08-29 12:31:34 +04:00
2015-05-21 10:11:12 +03:00
if ( sg_page ( sg ) = = virt_to_page ( buf ) & &
sg - > offset = = offset_in_page ( buf ) )
return ;
2007-08-29 12:31:34 +04:00
2015-05-21 10:11:12 +03:00
scatterwalk_start ( & walk , sg ) ;
2007-08-29 12:31:34 +04:00
scatterwalk_copychunks ( buf , & walk , nbytes , out ) ;
scatterwalk_done ( & walk , out , 0 ) ;
}
EXPORT_SYMBOL_GPL ( scatterwalk_map_and_copy ) ;
2013-08-18 06:42:22 +04:00
2015-05-21 10:10:59 +03:00
struct scatterlist * scatterwalk_ffwd ( struct scatterlist dst [ 2 ] ,
struct scatterlist * src ,
unsigned int len )
{
for ( ; ; ) {
if ( ! len )
return src ;
if ( src - > length > len )
break ;
len - = src - > length ;
src = sg_next ( src ) ;
}
2015-05-27 09:37:27 +03:00
sg_init_table ( dst , 2 ) ;
2015-05-21 10:10:59 +03:00
sg_set_page ( dst , sg_page ( src ) , src - > length - len , src - > offset + len ) ;
scatterwalk_crypto_chain ( dst , sg_next ( src ) , 0 , 2 ) ;
return dst ;
}
EXPORT_SYMBOL_GPL ( scatterwalk_ffwd ) ;