|
10 | 10 | */ |
11 | 11 |
|
12 | 12 | #include <crypto/scatterwalk.h> |
13 | | -#include <linux/crypto.h> |
14 | | -#include <linux/errno.h> |
15 | 13 | #include <linux/kernel.h> |
16 | 14 | #include <linux/mm.h> |
17 | 15 | #include <linux/module.h> |
18 | 16 | #include <linux/scatterlist.h> |
19 | | -#include <linux/slab.h> |
20 | | - |
21 | | -enum { |
22 | | - SKCIPHER_WALK_SLOW = 1 << 0, |
23 | | - SKCIPHER_WALK_COPY = 1 << 1, |
24 | | - SKCIPHER_WALK_DIFF = 1 << 2, |
25 | | - SKCIPHER_WALK_SLEEP = 1 << 3, |
26 | | -}; |
27 | | - |
28 | | -static inline gfp_t skcipher_walk_gfp(struct skcipher_walk *walk) |
29 | | -{ |
30 | | - return walk->flags & SKCIPHER_WALK_SLEEP ? GFP_KERNEL : GFP_ATOMIC; |
31 | | -} |
32 | 17 |
|
33 | 18 | void scatterwalk_skip(struct scatter_walk *walk, unsigned int nbytes) |
34 | 19 | { |
@@ -217,236 +202,3 @@ struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2], |
217 | 202 | return dst; |
218 | 203 | } |
219 | 204 | EXPORT_SYMBOL_GPL(scatterwalk_ffwd); |
220 | | - |
221 | | -static int skcipher_next_slow(struct skcipher_walk *walk, unsigned int bsize) |
222 | | -{ |
223 | | - unsigned alignmask = walk->alignmask; |
224 | | - unsigned n; |
225 | | - void *buffer; |
226 | | - |
227 | | - if (!walk->buffer) |
228 | | - walk->buffer = walk->page; |
229 | | - buffer = walk->buffer; |
230 | | - if (!buffer) { |
231 | | - /* Min size for a buffer of bsize bytes aligned to alignmask */ |
232 | | - n = bsize + (alignmask & ~(crypto_tfm_ctx_alignment() - 1)); |
233 | | - |
234 | | - buffer = kzalloc(n, skcipher_walk_gfp(walk)); |
235 | | - if (!buffer) |
236 | | - return skcipher_walk_done(walk, -ENOMEM); |
237 | | - walk->buffer = buffer; |
238 | | - } |
239 | | - |
240 | | - buffer = PTR_ALIGN(buffer, alignmask + 1); |
241 | | - memcpy_from_scatterwalk(buffer, &walk->in, bsize); |
242 | | - walk->out.__addr = buffer; |
243 | | - walk->in.__addr = walk->out.addr; |
244 | | - |
245 | | - walk->nbytes = bsize; |
246 | | - walk->flags |= SKCIPHER_WALK_SLOW; |
247 | | - |
248 | | - return 0; |
249 | | -} |
250 | | - |
251 | | -static int skcipher_next_copy(struct skcipher_walk *walk) |
252 | | -{ |
253 | | - void *tmp = walk->page; |
254 | | - |
255 | | - scatterwalk_map(&walk->in); |
256 | | - memcpy(tmp, walk->in.addr, walk->nbytes); |
257 | | - scatterwalk_unmap(&walk->in); |
258 | | - /* |
259 | | - * walk->in is advanced later when the number of bytes actually |
260 | | - * processed (which might be less than walk->nbytes) is known. |
261 | | - */ |
262 | | - |
263 | | - walk->in.__addr = tmp; |
264 | | - walk->out.__addr = tmp; |
265 | | - return 0; |
266 | | -} |
267 | | - |
268 | | -static int skcipher_next_fast(struct skcipher_walk *walk) |
269 | | -{ |
270 | | - unsigned long diff; |
271 | | - |
272 | | - diff = offset_in_page(walk->in.offset) - |
273 | | - offset_in_page(walk->out.offset); |
274 | | - diff |= (u8 *)(sg_page(walk->in.sg) + (walk->in.offset >> PAGE_SHIFT)) - |
275 | | - (u8 *)(sg_page(walk->out.sg) + (walk->out.offset >> PAGE_SHIFT)); |
276 | | - |
277 | | - scatterwalk_map(&walk->out); |
278 | | - walk->in.__addr = walk->out.__addr; |
279 | | - |
280 | | - if (diff) { |
281 | | - walk->flags |= SKCIPHER_WALK_DIFF; |
282 | | - scatterwalk_map(&walk->in); |
283 | | - } |
284 | | - |
285 | | - return 0; |
286 | | -} |
287 | | - |
288 | | -static int skcipher_walk_next(struct skcipher_walk *walk) |
289 | | -{ |
290 | | - unsigned int bsize; |
291 | | - unsigned int n; |
292 | | - |
293 | | - n = walk->total; |
294 | | - bsize = min(walk->stride, max(n, walk->blocksize)); |
295 | | - n = scatterwalk_clamp(&walk->in, n); |
296 | | - n = scatterwalk_clamp(&walk->out, n); |
297 | | - |
298 | | - if (unlikely(n < bsize)) { |
299 | | - if (unlikely(walk->total < walk->blocksize)) |
300 | | - return skcipher_walk_done(walk, -EINVAL); |
301 | | - |
302 | | -slow_path: |
303 | | - return skcipher_next_slow(walk, bsize); |
304 | | - } |
305 | | - walk->nbytes = n; |
306 | | - |
307 | | - if (unlikely((walk->in.offset | walk->out.offset) & walk->alignmask)) { |
308 | | - if (!walk->page) { |
309 | | - gfp_t gfp = skcipher_walk_gfp(walk); |
310 | | - |
311 | | - walk->page = (void *)__get_free_page(gfp); |
312 | | - if (!walk->page) |
313 | | - goto slow_path; |
314 | | - } |
315 | | - walk->flags |= SKCIPHER_WALK_COPY; |
316 | | - return skcipher_next_copy(walk); |
317 | | - } |
318 | | - |
319 | | - return skcipher_next_fast(walk); |
320 | | -} |
321 | | - |
322 | | -static int skcipher_copy_iv(struct skcipher_walk *walk) |
323 | | -{ |
324 | | - unsigned alignmask = walk->alignmask; |
325 | | - unsigned ivsize = walk->ivsize; |
326 | | - unsigned aligned_stride = ALIGN(walk->stride, alignmask + 1); |
327 | | - unsigned size; |
328 | | - u8 *iv; |
329 | | - |
330 | | - /* Min size for a buffer of stride + ivsize, aligned to alignmask */ |
331 | | - size = aligned_stride + ivsize + |
332 | | - (alignmask & ~(crypto_tfm_ctx_alignment() - 1)); |
333 | | - |
334 | | - walk->buffer = kmalloc(size, skcipher_walk_gfp(walk)); |
335 | | - if (!walk->buffer) |
336 | | - return -ENOMEM; |
337 | | - |
338 | | - iv = PTR_ALIGN(walk->buffer, alignmask + 1) + aligned_stride; |
339 | | - |
340 | | - walk->iv = memcpy(iv, walk->iv, walk->ivsize); |
341 | | - return 0; |
342 | | -} |
343 | | - |
344 | | -int skcipher_walk_first(struct skcipher_walk *walk, bool atomic) |
345 | | -{ |
346 | | - if (WARN_ON_ONCE(in_hardirq())) |
347 | | - return -EDEADLK; |
348 | | - |
349 | | - walk->flags = atomic ? 0 : SKCIPHER_WALK_SLEEP; |
350 | | - |
351 | | - walk->buffer = NULL; |
352 | | - if (unlikely(((unsigned long)walk->iv & walk->alignmask))) { |
353 | | - int err = skcipher_copy_iv(walk); |
354 | | - if (err) |
355 | | - return err; |
356 | | - } |
357 | | - |
358 | | - walk->page = NULL; |
359 | | - |
360 | | - return skcipher_walk_next(walk); |
361 | | -} |
362 | | -EXPORT_SYMBOL_GPL(skcipher_walk_first); |
363 | | - |
364 | | -/** |
365 | | - * skcipher_walk_done() - finish one step of a skcipher_walk |
366 | | - * @walk: the skcipher_walk |
367 | | - * @res: number of bytes *not* processed (>= 0) from walk->nbytes, |
368 | | - * or a -errno value to terminate the walk due to an error |
369 | | - * |
370 | | - * This function cleans up after one step of walking through the source and |
371 | | - * destination scatterlists, and advances to the next step if applicable. |
372 | | - * walk->nbytes is set to the number of bytes available in the next step, |
373 | | - * walk->total is set to the new total number of bytes remaining, and |
374 | | - * walk->{src,dst}.virt.addr is set to the next pair of data pointers. If there |
375 | | - * is no more data, or if an error occurred (i.e. -errno return), then |
376 | | - * walk->nbytes and walk->total are set to 0 and all resources owned by the |
377 | | - * skcipher_walk are freed. |
378 | | - * |
379 | | - * Return: 0 or a -errno value. If @res was a -errno value then it will be |
380 | | - * returned, but other errors may occur too. |
381 | | - */ |
382 | | -int skcipher_walk_done(struct skcipher_walk *walk, int res) |
383 | | -{ |
384 | | - unsigned int n = walk->nbytes; /* num bytes processed this step */ |
385 | | - unsigned int total = 0; /* new total remaining */ |
386 | | - |
387 | | - if (!n) |
388 | | - goto finish; |
389 | | - |
390 | | - if (likely(res >= 0)) { |
391 | | - n -= res; /* subtract num bytes *not* processed */ |
392 | | - total = walk->total - n; |
393 | | - } |
394 | | - |
395 | | - if (likely(!(walk->flags & (SKCIPHER_WALK_SLOW | |
396 | | - SKCIPHER_WALK_COPY | |
397 | | - SKCIPHER_WALK_DIFF)))) { |
398 | | - scatterwalk_advance(&walk->in, n); |
399 | | - } else if (walk->flags & SKCIPHER_WALK_DIFF) { |
400 | | - scatterwalk_done_src(&walk->in, n); |
401 | | - } else if (walk->flags & SKCIPHER_WALK_COPY) { |
402 | | - scatterwalk_advance(&walk->in, n); |
403 | | - scatterwalk_map(&walk->out); |
404 | | - memcpy(walk->out.addr, walk->page, n); |
405 | | - } else { /* SKCIPHER_WALK_SLOW */ |
406 | | - if (res > 0) { |
407 | | - /* |
408 | | - * Didn't process all bytes. Either the algorithm is |
409 | | - * broken, or this was the last step and it turned out |
410 | | - * the message wasn't evenly divisible into blocks but |
411 | | - * the algorithm requires it. |
412 | | - */ |
413 | | - res = -EINVAL; |
414 | | - total = 0; |
415 | | - } else |
416 | | - memcpy_to_scatterwalk(&walk->out, walk->out.addr, n); |
417 | | - goto dst_done; |
418 | | - } |
419 | | - |
420 | | - scatterwalk_done_dst(&walk->out, n); |
421 | | -dst_done: |
422 | | - |
423 | | - if (res > 0) |
424 | | - res = 0; |
425 | | - |
426 | | - walk->total = total; |
427 | | - walk->nbytes = 0; |
428 | | - |
429 | | - if (total) { |
430 | | - if (walk->flags & SKCIPHER_WALK_SLEEP) |
431 | | - cond_resched(); |
432 | | - walk->flags &= ~(SKCIPHER_WALK_SLOW | SKCIPHER_WALK_COPY | |
433 | | - SKCIPHER_WALK_DIFF); |
434 | | - return skcipher_walk_next(walk); |
435 | | - } |
436 | | - |
437 | | -finish: |
438 | | - /* Short-circuit for the common/fast path. */ |
439 | | - if (!((unsigned long)walk->buffer | (unsigned long)walk->page)) |
440 | | - goto out; |
441 | | - |
442 | | - if (walk->iv != walk->oiv) |
443 | | - memcpy(walk->oiv, walk->iv, walk->ivsize); |
444 | | - if (walk->buffer != walk->page) |
445 | | - kfree(walk->buffer); |
446 | | - if (walk->page) |
447 | | - free_page((unsigned long)walk->page); |
448 | | - |
449 | | -out: |
450 | | - return res; |
451 | | -} |
452 | | -EXPORT_SYMBOL_GPL(skcipher_walk_done); |
0 commit comments