scatterwalk.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. * Cryptographic API.
  3. *
  4. * Cipher operations.
  5. *
  6. * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  7. * 2002 Adam J. Richter <adam@yggdrasil.com>
  8. * 2004 Jean-Luc Cooke <jlcooke@certainkey.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by the Free
  12. * Software Foundation; either version 2 of the License, or (at your option)
  13. * any later version.
  14. *
  15. */
  16. #include <crypto/scatterwalk.h>
  17. #include <linux/kernel.h>
  18. #include <linux/mm.h>
  19. #include <linux/module.h>
  20. #include <linux/scatterlist.h>
  21. static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
  22. {
  23. void *src = out ? buf : sgdata;
  24. void *dst = out ? sgdata : buf;
  25. memcpy(dst, src, nbytes);
  26. }
  27. void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
  28. size_t nbytes, int out)
  29. {
  30. for (;;) {
  31. unsigned int len_this_page = scatterwalk_pagelen(walk);
  32. u8 *vaddr;
  33. if (len_this_page > nbytes)
  34. len_this_page = nbytes;
  35. if (out != 2) {
  36. vaddr = scatterwalk_map(walk);
  37. memcpy_dir(buf, vaddr, len_this_page, out);
  38. scatterwalk_unmap(vaddr);
  39. }
  40. scatterwalk_advance(walk, len_this_page);
  41. if (nbytes == len_this_page)
  42. break;
  43. buf += len_this_page;
  44. nbytes -= len_this_page;
  45. scatterwalk_pagedone(walk, out & 1, 1);
  46. }
  47. }
  48. EXPORT_SYMBOL_GPL(scatterwalk_copychunks);
  49. void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
  50. unsigned int start, unsigned int nbytes, int out)
  51. {
  52. struct scatter_walk walk;
  53. struct scatterlist tmp[2];
  54. if (!nbytes)
  55. return;
  56. sg = scatterwalk_ffwd(tmp, sg, start);
  57. scatterwalk_start(&walk, sg);
  58. scatterwalk_copychunks(buf, &walk, nbytes, out);
  59. scatterwalk_done(&walk, out, 0);
  60. }
  61. EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy);
  62. struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2],
  63. struct scatterlist *src,
  64. unsigned int len)
  65. {
  66. for (;;) {
  67. if (!len)
  68. return src;
  69. if (src->length > len)
  70. break;
  71. len -= src->length;
  72. src = sg_next(src);
  73. }
  74. sg_init_table(dst, 2);
  75. sg_set_page(dst, sg_page(src), src->length - len, src->offset + len);
  76. scatterwalk_crypto_chain(dst, sg_next(src), 0, 2);
  77. return dst;
  78. }
  79. EXPORT_SYMBOL_GPL(scatterwalk_ffwd);