linux/crypto/scatterwalk.c
<<
>>
Prefs
   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
  18static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
  19{
  20        void *src = out ? buf : sgdata;
  21        void *dst = out ? sgdata : buf;
  22
  23        memcpy(dst, src, nbytes);
  24}
  25
  26void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
  27                            size_t nbytes, int out)
  28{
  29        for (;;) {
  30                unsigned int len_this_page = scatterwalk_pagelen(walk);
  31                u8 *vaddr;
  32
  33                if (len_this_page > nbytes)
  34                        len_this_page = nbytes;
  35
  36                if (out != 2) {
  37                        vaddr = scatterwalk_map(walk);
  38                        memcpy_dir(buf, vaddr, len_this_page, out);
  39                        scatterwalk_unmap(vaddr);
  40                }
  41
  42                scatterwalk_advance(walk, len_this_page);
  43
  44                if (nbytes == len_this_page)
  45                        break;
  46
  47                buf += len_this_page;
  48                nbytes -= len_this_page;
  49
  50                scatterwalk_pagedone(walk, out & 1, 1);
  51        }
  52}
  53EXPORT_SYMBOL_GPL(scatterwalk_copychunks);
  54
  55void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
  56                              unsigned int start, unsigned int nbytes, int out)
  57{
  58        struct scatter_walk walk;
  59        struct scatterlist tmp[2];
  60
  61        if (!nbytes)
  62                return;
  63
  64        sg = scatterwalk_ffwd(tmp, sg, start);
  65
  66        scatterwalk_start(&walk, sg);
  67        scatterwalk_copychunks(buf, &walk, nbytes, out);
  68        scatterwalk_done(&walk, out, 0);
  69}
  70EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy);
  71
  72struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2],
  73                                     struct scatterlist *src,
  74                                     unsigned int len)
  75{
  76        for (;;) {
  77                if (!len)
  78                        return src;
  79
  80                if (src->length > len)
  81                        break;
  82
  83                len -= src->length;
  84                src = sg_next(src);
  85        }
  86
  87        sg_init_table(dst, 2);
  88        sg_set_page(dst, sg_page(src), src->length - len, src->offset + len);
  89        scatterwalk_crypto_chain(dst, sg_next(src), 2);
  90
  91        return dst;
  92}
  93EXPORT_SYMBOL_GPL(scatterwalk_ffwd);
  94