scatterwalk.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  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. if (sg_page(sg) == virt_to_page(buf) &&
  58. sg->offset == offset_in_page(buf))
  59. return;
  60. scatterwalk_start(&walk, sg);
  61. scatterwalk_copychunks(buf, &walk, nbytes, out);
  62. scatterwalk_done(&walk, out, 0);
  63. }
  64. EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy);
  65. struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2],
  66. struct scatterlist *src,
  67. unsigned int len)
  68. {
  69. for (;;) {
  70. if (!len)
  71. return src;
  72. if (src->length > len)
  73. break;
  74. len -= src->length;
  75. src = sg_next(src);
  76. }
  77. sg_init_table(dst, 2);
  78. sg_set_page(dst, sg_page(src), src->length - len, src->offset + len);
  79. scatterwalk_crypto_chain(dst, sg_next(src), 0, 2);
  80. return dst;
  81. }
  82. EXPORT_SYMBOL_GPL(scatterwalk_ffwd);