Blame view

crypto/scatterwalk.c 2.95 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * 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.
   *
   */
42c271c6c   Herbert Xu   [CRYPTO] scatterw...
16
17
  
  #include <crypto/scatterwalk.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  #include <linux/kernel.h>
  #include <linux/mm.h>
5c64097aa   Herbert Xu   [CRYPTO] scatterw...
20
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  #include <linux/pagemap.h>
  #include <linux/highmem.h>
5c64097aa   Herbert Xu   [CRYPTO] scatterw...
23
  #include <linux/scatterlist.h>
5c64097aa   Herbert Xu   [CRYPTO] scatterw...
24
  static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  {
5c64097aa   Herbert Xu   [CRYPTO] scatterw...
26
27
28
29
  	void *src = out ? buf : sgdata;
  	void *dst = out ? sgdata : buf;
  
  	memcpy(dst, src, nbytes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
  }
  
  void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  	walk->sg = sg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  	BUG_ON(!sg->length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
  	walk->offset = sg->offset;
  }
5c64097aa   Herbert Xu   [CRYPTO] scatterw...
38
  EXPORT_SYMBOL_GPL(scatterwalk_start);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39

5c64097aa   Herbert Xu   [CRYPTO] scatterw...
40
  void *scatterwalk_map(struct scatter_walk *walk, int out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  {
5c64097aa   Herbert Xu   [CRYPTO] scatterw...
42
43
  	return crypto_kmap(scatterwalk_page(walk), out) +
  	       offset_in_page(walk->offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  }
5c64097aa   Herbert Xu   [CRYPTO] scatterw...
45
  EXPORT_SYMBOL_GPL(scatterwalk_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
  
  static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
  				 unsigned int more)
  {
9f1167272   Herbert Xu   [CRYPTO] api: Flu...
50
51
  	if (out) {
  		struct page *page;
78c2f0b8c   Jens Axboe   [SG] Update crypt...
52
  		page = sg_page(walk->sg) + ((walk->offset - 1) >> PAGE_SHIFT);
4f3e797ad   Herbert Xu   crypto: scatterwa...
53
54
  		if (!PageSlab(page))
  			flush_dcache_page(page);
9f1167272   Herbert Xu   [CRYPTO] api: Flu...
55
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
  
  	if (more) {
5c64097aa   Herbert Xu   [CRYPTO] scatterw...
58
59
60
  		walk->offset += PAGE_SIZE - 1;
  		walk->offset &= PAGE_MASK;
  		if (walk->offset >= walk->sg->offset + walk->sg->length)
b2ab4a57b   Herbert Xu   [CRYPTO] scatterw...
61
  			scatterwalk_start(walk, scatterwalk_sg_next(walk->sg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
  	}
  }
  
  void scatterwalk_done(struct scatter_walk *walk, int out, int more)
  {
85c6201a8   David S. Miller   crypto: scatterwa...
67
  	if (!(scatterwalk_pagelen(walk) & (PAGE_SIZE - 1)) || !more)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
  		scatterwalk_pagedone(walk, out, more);
  }
5c64097aa   Herbert Xu   [CRYPTO] scatterw...
70
  EXPORT_SYMBOL_GPL(scatterwalk_done);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71

5c64097aa   Herbert Xu   [CRYPTO] scatterw...
72
73
  void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
  			    size_t nbytes, int out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  {
5c64097aa   Herbert Xu   [CRYPTO] scatterw...
75
76
77
78
79
80
81
82
83
84
  	for (;;) {
  		unsigned int len_this_page = scatterwalk_pagelen(walk);
  		u8 *vaddr;
  
  		if (len_this_page > nbytes)
  			len_this_page = nbytes;
  
  		vaddr = scatterwalk_map(walk, out);
  		memcpy_dir(buf, vaddr, len_this_page, out);
  		scatterwalk_unmap(vaddr, out);
4ee531a3e   Herbert Xu   [CRYPTO] api: Use...
85
  		scatterwalk_advance(walk, len_this_page);
f70ee5ec8   J. Bruce Fields   [CRYPTO] api: sca...
86

5c64097aa   Herbert Xu   [CRYPTO] scatterw...
87
88
89
90
91
  		if (nbytes == len_this_page)
  			break;
  
  		buf += len_this_page;
  		nbytes -= len_this_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  		scatterwalk_pagedone(walk, out, 1);
c774e93e2   Herbert Xu   [CRYPTO] Add plum...
94
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  }
5c64097aa   Herbert Xu   [CRYPTO] scatterw...
96
  EXPORT_SYMBOL_GPL(scatterwalk_copychunks);
5fa0fea27   Herbert Xu   [CRYPTO] scatterw...
97
98
99
100
101
102
  
  void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
  			      unsigned int start, unsigned int nbytes, int out)
  {
  	struct scatter_walk walk;
  	unsigned int offset = 0;
6e050778c   Herbert Xu   [CRYPTO] scatterw...
103
104
  	if (!nbytes)
  		return;
5fa0fea27   Herbert Xu   [CRYPTO] scatterw...
105
106
107
108
109
110
111
  	for (;;) {
  		scatterwalk_start(&walk, sg);
  
  		if (start < offset + sg->length)
  			break;
  
  		offset += sg->length;
b2ab4a57b   Herbert Xu   [CRYPTO] scatterw...
112
  		sg = scatterwalk_sg_next(sg);
5fa0fea27   Herbert Xu   [CRYPTO] scatterw...
113
114
115
116
117
118
119
  	}
  
  	scatterwalk_advance(&walk, start - offset);
  	scatterwalk_copychunks(buf, &walk, nbytes, out);
  	scatterwalk_done(&walk, out, 0);
  }
  EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy);