Merge commit 'v2.6.39-rc6' into x86/cleanups
[pandora-kernel.git] / drivers / staging / pohmelfs / crypto.c
1 /*
2  * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include <linux/crypto.h>
17 #include <linux/highmem.h>
18 #include <linux/kthread.h>
19 #include <linux/pagemap.h>
20 #include <linux/slab.h>
21
22 #include "netfs.h"
23
24 static struct crypto_hash *pohmelfs_init_hash(struct pohmelfs_sb *psb)
25 {
26         int err;
27         struct crypto_hash *hash;
28
29         hash = crypto_alloc_hash(psb->hash_string, 0, CRYPTO_ALG_ASYNC);
30         if (IS_ERR(hash)) {
31                 err = PTR_ERR(hash);
32                 dprintk("%s: idx: %u: failed to allocate hash '%s', err: %d.\n",
33                                 __func__, psb->idx, psb->hash_string, err);
34                 goto err_out_exit;
35         }
36
37         psb->crypto_attached_size = crypto_hash_digestsize(hash);
38
39         if (!psb->hash_keysize)
40                 return hash;
41
42         err = crypto_hash_setkey(hash, psb->hash_key, psb->hash_keysize);
43         if (err) {
44                 dprintk("%s: idx: %u: failed to set key for hash '%s', err: %d.\n",
45                                 __func__, psb->idx, psb->hash_string, err);
46                 goto err_out_free;
47         }
48
49         return hash;
50
51 err_out_free:
52         crypto_free_hash(hash);
53 err_out_exit:
54         return ERR_PTR(err);
55 }
56
57 static struct crypto_ablkcipher *pohmelfs_init_cipher(struct pohmelfs_sb *psb)
58 {
59         int err = -EINVAL;
60         struct crypto_ablkcipher *cipher;
61
62         if (!psb->cipher_keysize)
63                 goto err_out_exit;
64
65         cipher = crypto_alloc_ablkcipher(psb->cipher_string, 0, 0);
66         if (IS_ERR(cipher)) {
67                 err = PTR_ERR(cipher);
68                 dprintk("%s: idx: %u: failed to allocate cipher '%s', err: %d.\n",
69                                 __func__, psb->idx, psb->cipher_string, err);
70                 goto err_out_exit;
71         }
72
73         crypto_ablkcipher_clear_flags(cipher, ~0);
74
75         err = crypto_ablkcipher_setkey(cipher, psb->cipher_key, psb->cipher_keysize);
76         if (err) {
77                 dprintk("%s: idx: %u: failed to set key for cipher '%s', err: %d.\n",
78                                 __func__, psb->idx, psb->cipher_string, err);
79                 goto err_out_free;
80         }
81
82         return cipher;
83
84 err_out_free:
85         crypto_free_ablkcipher(cipher);
86 err_out_exit:
87         return ERR_PTR(err);
88 }
89
90 int pohmelfs_crypto_engine_init(struct pohmelfs_crypto_engine *e, struct pohmelfs_sb *psb)
91 {
92         int err;
93
94         e->page_num = 0;
95
96         e->size = PAGE_SIZE;
97         e->data = kmalloc(e->size, GFP_KERNEL);
98         if (!e->data) {
99                 err = -ENOMEM;
100                 goto err_out_exit;
101         }
102
103         if (psb->hash_string) {
104                 e->hash = pohmelfs_init_hash(psb);
105                 if (IS_ERR(e->hash)) {
106                         err = PTR_ERR(e->hash);
107                         e->hash = NULL;
108                         goto err_out_free;
109                 }
110         }
111
112         if (psb->cipher_string) {
113                 e->cipher = pohmelfs_init_cipher(psb);
114                 if (IS_ERR(e->cipher)) {
115                         err = PTR_ERR(e->cipher);
116                         e->cipher = NULL;
117                         goto err_out_free_hash;
118                 }
119         }
120
121         return 0;
122
123 err_out_free_hash:
124         crypto_free_hash(e->hash);
125 err_out_free:
126         kfree(e->data);
127 err_out_exit:
128         return err;
129 }
130
131 void pohmelfs_crypto_engine_exit(struct pohmelfs_crypto_engine *e)
132 {
133         crypto_free_hash(e->hash);
134         crypto_free_ablkcipher(e->cipher);
135         kfree(e->data);
136 }
137
138 static void pohmelfs_crypto_complete(struct crypto_async_request *req, int err)
139 {
140         struct pohmelfs_crypto_completion *c = req->data;
141
142         if (err == -EINPROGRESS)
143                 return;
144
145         dprintk("%s: req: %p, err: %d.\n", __func__, req, err);
146         c->error = err;
147         complete(&c->complete);
148 }
149
150 static int pohmelfs_crypto_process(struct ablkcipher_request *req,
151                 struct scatterlist *sg_dst, struct scatterlist *sg_src,
152                 void *iv, int enc, unsigned long timeout)
153 {
154         struct pohmelfs_crypto_completion complete;
155         int err;
156
157         init_completion(&complete.complete);
158         complete.error = -EINPROGRESS;
159
160         ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
161                                         pohmelfs_crypto_complete, &complete);
162
163         ablkcipher_request_set_crypt(req, sg_src, sg_dst, sg_src->length, iv);
164
165         if (enc)
166                 err = crypto_ablkcipher_encrypt(req);
167         else
168                 err = crypto_ablkcipher_decrypt(req);
169
170         switch (err) {
171         case -EINPROGRESS:
172         case -EBUSY:
173                 err = wait_for_completion_interruptible_timeout(&complete.complete,
174                                         timeout);
175                 if (!err)
176                         err = -ETIMEDOUT;
177                 else if (err > 0)
178                         err = complete.error;
179                 break;
180         default:
181                 break;
182         }
183
184         return err;
185 }
186
187 int pohmelfs_crypto_process_input_data(struct pohmelfs_crypto_engine *e, u64 cmd_iv,
188                 void *data, struct page *page, unsigned int size)
189 {
190         int err;
191         struct scatterlist sg;
192
193         if (!e->cipher && !e->hash)
194                 return 0;
195
196         dprintk("%s: eng: %p, iv: %llx, data: %p, page: %p/%lu, size: %u.\n",
197                 __func__, e, cmd_iv, data, page, (page) ? page->index : 0, size);
198
199         if (data) {
200                 sg_init_one(&sg, data, size);
201         } else {
202                 sg_init_table(&sg, 1);
203                 sg_set_page(&sg, page, size, 0);
204         }
205
206         if (e->cipher) {
207                 struct ablkcipher_request *req = e->data + crypto_hash_digestsize(e->hash);
208                 u8 iv[32];
209
210                 memset(iv, 0, sizeof(iv));
211                 memcpy(iv, &cmd_iv, sizeof(cmd_iv));
212
213                 ablkcipher_request_set_tfm(req, e->cipher);
214
215                 err = pohmelfs_crypto_process(req, &sg, &sg, iv, 0, e->timeout);
216                 if (err)
217                         goto err_out_exit;
218         }
219
220         if (e->hash) {
221                 struct hash_desc desc;
222                 void *dst = e->data + e->size/2;
223
224                 desc.tfm = e->hash;
225                 desc.flags = 0;
226
227                 err = crypto_hash_init(&desc);
228                 if (err)
229                         goto err_out_exit;
230
231                 err = crypto_hash_update(&desc, &sg, size);
232                 if (err)
233                         goto err_out_exit;
234
235                 err = crypto_hash_final(&desc, dst);
236                 if (err)
237                         goto err_out_exit;
238
239                 err = !!memcmp(dst, e->data, crypto_hash_digestsize(e->hash));
240
241                 if (err) {
242 #ifdef CONFIG_POHMELFS_DEBUG
243                         unsigned int i;
244                         unsigned char *recv = e->data, *calc = dst;
245
246                         dprintk("%s: eng: %p, hash: %p, cipher: %p: iv : %llx, hash mismatch (recv/calc): ",
247                                         __func__, e, e->hash, e->cipher, cmd_iv);
248                         for (i = 0; i < crypto_hash_digestsize(e->hash); ++i) {
249 #if 0
250                                 dprintka("%02x ", recv[i]);
251                                 if (recv[i] != calc[i]) {
252                                         dprintka("| calc byte: %02x.\n", calc[i]);
253                                         break;
254                                 }
255 #else
256                                 dprintka("%02x/%02x ", recv[i], calc[i]);
257 #endif
258                         }
259                         dprintk("\n");
260 #endif
261                         goto err_out_exit;
262                 } else {
263                         dprintk("%s: eng: %p, hash: %p, cipher: %p: hashes matched.\n",
264                                         __func__, e, e->hash, e->cipher);
265                 }
266         }
267
268         dprintk("%s: eng: %p, size: %u, hash: %p, cipher: %p: completed.\n",
269                         __func__, e, e->size, e->hash, e->cipher);
270
271         return 0;
272
273 err_out_exit:
274         dprintk("%s: eng: %p, hash: %p, cipher: %p: err: %d.\n",
275                         __func__, e, e->hash, e->cipher, err);
276         return err;
277 }
278
279 static int pohmelfs_trans_iter(struct netfs_trans *t, struct pohmelfs_crypto_engine *e,
280                 int (*iterator) (struct pohmelfs_crypto_engine *e,
281                                   struct scatterlist *dst,
282                                   struct scatterlist *src))
283 {
284         void *data = t->iovec.iov_base + sizeof(struct netfs_cmd) + t->psb->crypto_attached_size;
285         unsigned int size = t->iovec.iov_len - sizeof(struct netfs_cmd) - t->psb->crypto_attached_size;
286         struct netfs_cmd *cmd = data;
287         unsigned int sz, pages = t->attached_pages, i, csize, cmd_cmd, dpage_idx;
288         struct scatterlist sg_src, sg_dst;
289         int err;
290
291         while (size) {
292                 cmd = data;
293                 cmd_cmd = __be16_to_cpu(cmd->cmd);
294                 csize = __be32_to_cpu(cmd->size);
295                 cmd->iv = __cpu_to_be64(e->iv);
296
297                 if (cmd_cmd == NETFS_READ_PAGES || cmd_cmd == NETFS_READ_PAGE)
298                         csize = __be16_to_cpu(cmd->ext);
299
300                 sz = csize + __be16_to_cpu(cmd->cpad) + sizeof(struct netfs_cmd);
301
302                 dprintk("%s: size: %u, sz: %u, cmd_size: %u, cmd_cpad: %u.\n",
303                                 __func__, size, sz, __be32_to_cpu(cmd->size), __be16_to_cpu(cmd->cpad));
304
305                 data += sz;
306                 size -= sz;
307
308                 sg_init_one(&sg_src, cmd->data, sz - sizeof(struct netfs_cmd));
309                 sg_init_one(&sg_dst, cmd->data, sz - sizeof(struct netfs_cmd));
310
311                 err = iterator(e, &sg_dst, &sg_src);
312                 if (err)
313                         return err;
314         }
315
316         if (!pages)
317                 return 0;
318
319         dpage_idx = 0;
320         for (i = 0; i < t->page_num; ++i) {
321                 struct page *page = t->pages[i];
322                 struct page *dpage = e->pages[dpage_idx];
323
324                 if (!page)
325                         continue;
326
327                 sg_init_table(&sg_src, 1);
328                 sg_init_table(&sg_dst, 1);
329                 sg_set_page(&sg_src, page, page_private(page), 0);
330                 sg_set_page(&sg_dst, dpage, page_private(page), 0);
331
332                 err = iterator(e, &sg_dst, &sg_src);
333                 if (err)
334                         return err;
335
336                 pages--;
337                 if (!pages)
338                         break;
339                 dpage_idx++;
340         }
341
342         return 0;
343 }
344
345 static int pohmelfs_encrypt_iterator(struct pohmelfs_crypto_engine *e,
346                 struct scatterlist *sg_dst, struct scatterlist *sg_src)
347 {
348         struct ablkcipher_request *req = e->data;
349         u8 iv[32];
350
351         memset(iv, 0, sizeof(iv));
352
353         memcpy(iv, &e->iv, sizeof(e->iv));
354
355         return pohmelfs_crypto_process(req, sg_dst, sg_src, iv, 1, e->timeout);
356 }
357
358 static int pohmelfs_encrypt(struct pohmelfs_crypto_thread *tc)
359 {
360         struct netfs_trans *t = tc->trans;
361         struct pohmelfs_crypto_engine *e = &tc->eng;
362         struct ablkcipher_request *req = e->data;
363
364         memset(req, 0, sizeof(struct ablkcipher_request));
365         ablkcipher_request_set_tfm(req, e->cipher);
366
367         e->iv = pohmelfs_gen_iv(t);
368
369         return pohmelfs_trans_iter(t, e, pohmelfs_encrypt_iterator);
370 }
371
372 static int pohmelfs_hash_iterator(struct pohmelfs_crypto_engine *e,
373                 struct scatterlist *sg_dst, struct scatterlist *sg_src)
374 {
375         return crypto_hash_update(e->data, sg_src, sg_src->length);
376 }
377
378 static int pohmelfs_hash(struct pohmelfs_crypto_thread *tc)
379 {
380         struct pohmelfs_crypto_engine *e = &tc->eng;
381         struct hash_desc *desc = e->data;
382         unsigned char *dst = tc->trans->iovec.iov_base + sizeof(struct netfs_cmd);
383         int err;
384
385         desc->tfm = e->hash;
386         desc->flags = 0;
387
388         err = crypto_hash_init(desc);
389         if (err)
390                 return err;
391
392         err = pohmelfs_trans_iter(tc->trans, e, pohmelfs_hash_iterator);
393         if (err)
394                 return err;
395
396         err = crypto_hash_final(desc, dst);
397         if (err)
398                 return err;
399
400         {
401                 unsigned int i;
402                 dprintk("%s: ", __func__);
403                 for (i = 0; i < tc->psb->crypto_attached_size; ++i)
404                         dprintka("%02x ", dst[i]);
405                 dprintka("\n");
406         }
407
408         return 0;
409 }
410
411 static void pohmelfs_crypto_pages_free(struct pohmelfs_crypto_engine *e)
412 {
413         unsigned int i;
414
415         for (i = 0; i < e->page_num; ++i)
416                 __free_page(e->pages[i]);
417         kfree(e->pages);
418 }
419
420 static int pohmelfs_crypto_pages_alloc(struct pohmelfs_crypto_engine *e, struct pohmelfs_sb *psb)
421 {
422         unsigned int i;
423
424         e->pages = kmalloc(psb->trans_max_pages * sizeof(struct page *), GFP_KERNEL);
425         if (!e->pages)
426                 return -ENOMEM;
427
428         for (i = 0; i < psb->trans_max_pages; ++i) {
429                 e->pages[i] = alloc_page(GFP_KERNEL);
430                 if (!e->pages[i])
431                         break;
432         }
433
434         e->page_num = i;
435         if (!e->page_num)
436                 goto err_out_free;
437
438         return 0;
439
440 err_out_free:
441         kfree(e->pages);
442         return -ENOMEM;
443 }
444
445 static void pohmelfs_sys_crypto_exit_one(struct pohmelfs_crypto_thread *t)
446 {
447         struct pohmelfs_sb *psb = t->psb;
448
449         if (t->thread)
450                 kthread_stop(t->thread);
451
452         mutex_lock(&psb->crypto_thread_lock);
453         list_del(&t->thread_entry);
454         psb->crypto_thread_num--;
455         mutex_unlock(&psb->crypto_thread_lock);
456
457         pohmelfs_crypto_engine_exit(&t->eng);
458         pohmelfs_crypto_pages_free(&t->eng);
459         kfree(t);
460 }
461
462 static int pohmelfs_crypto_finish(struct netfs_trans *t, struct pohmelfs_sb *psb, int err)
463 {
464         struct netfs_cmd *cmd = t->iovec.iov_base;
465         netfs_convert_cmd(cmd);
466
467         if (likely(!err))
468                 err = netfs_trans_finish_send(t, psb);
469
470         t->result = err;
471         netfs_trans_put(t);
472
473         return err;
474 }
475
476 void pohmelfs_crypto_thread_make_ready(struct pohmelfs_crypto_thread *th)
477 {
478         struct pohmelfs_sb *psb = th->psb;
479
480         th->page = NULL;
481         th->trans = NULL;
482
483         mutex_lock(&psb->crypto_thread_lock);
484         list_move_tail(&th->thread_entry, &psb->crypto_ready_list);
485         mutex_unlock(&psb->crypto_thread_lock);
486         wake_up(&psb->wait);
487 }
488
489 static int pohmelfs_crypto_thread_trans(struct pohmelfs_crypto_thread *t)
490 {
491         struct netfs_trans *trans;
492         int err = 0;
493
494         trans = t->trans;
495         trans->eng = NULL;
496
497         if (t->eng.hash) {
498                 err = pohmelfs_hash(t);
499                 if (err)
500                         goto out_complete;
501         }
502
503         if (t->eng.cipher) {
504                 err = pohmelfs_encrypt(t);
505                 if (err)
506                         goto out_complete;
507                 trans->eng = &t->eng;
508         }
509
510 out_complete:
511         t->page = NULL;
512         t->trans = NULL;
513
514         if (!trans->eng)
515                 pohmelfs_crypto_thread_make_ready(t);
516
517         pohmelfs_crypto_finish(trans, t->psb, err);
518         return err;
519 }
520
521 static int pohmelfs_crypto_thread_page(struct pohmelfs_crypto_thread *t)
522 {
523         struct pohmelfs_crypto_engine *e = &t->eng;
524         struct page *page = t->page;
525         int err;
526
527         WARN_ON(!PageChecked(page));
528
529         err = pohmelfs_crypto_process_input_data(e, e->iv, NULL, page, t->size);
530         if (!err)
531                 SetPageUptodate(page);
532         else
533                 SetPageError(page);
534         unlock_page(page);
535         page_cache_release(page);
536
537         pohmelfs_crypto_thread_make_ready(t);
538
539         return err;
540 }
541
542 static int pohmelfs_crypto_thread_func(void *data)
543 {
544         struct pohmelfs_crypto_thread *t = data;
545
546         while (!kthread_should_stop()) {
547                 wait_event_interruptible(t->wait, kthread_should_stop() ||
548                                 t->trans || t->page);
549
550                 if (kthread_should_stop())
551                         break;
552
553                 if (!t->trans && !t->page)
554                         continue;
555
556                 dprintk("%s: thread: %p, trans: %p, page: %p.\n",
557                                 __func__, t, t->trans, t->page);
558
559                 if (t->trans)
560                         pohmelfs_crypto_thread_trans(t);
561                 else if (t->page)
562                         pohmelfs_crypto_thread_page(t);
563         }
564
565         return 0;
566 }
567
568 static void pohmelfs_crypto_flush(struct pohmelfs_sb *psb, struct list_head *head)
569 {
570         while (!list_empty(head)) {
571                 struct pohmelfs_crypto_thread *t = NULL;
572
573                 mutex_lock(&psb->crypto_thread_lock);
574                 if (!list_empty(head)) {
575                         t = list_first_entry(head, struct pohmelfs_crypto_thread, thread_entry);
576                         list_del_init(&t->thread_entry);
577                 }
578                 mutex_unlock(&psb->crypto_thread_lock);
579
580                 if (t)
581                         pohmelfs_sys_crypto_exit_one(t);
582         }
583 }
584
585 static void pohmelfs_sys_crypto_exit(struct pohmelfs_sb *psb)
586 {
587         while (!list_empty(&psb->crypto_active_list) || !list_empty(&psb->crypto_ready_list)) {
588                 dprintk("%s: crypto_thread_num: %u.\n", __func__, psb->crypto_thread_num);
589                 pohmelfs_crypto_flush(psb, &psb->crypto_active_list);
590                 pohmelfs_crypto_flush(psb, &psb->crypto_ready_list);
591         }
592 }
593
594 static int pohmelfs_sys_crypto_init(struct pohmelfs_sb *psb)
595 {
596         unsigned int i;
597         struct pohmelfs_crypto_thread *t;
598         struct pohmelfs_config *c;
599         struct netfs_state *st;
600         int err;
601
602         list_for_each_entry(c, &psb->state_list, config_entry) {
603                 st = &c->state;
604
605                 err = pohmelfs_crypto_engine_init(&st->eng, psb);
606                 if (err)
607                         goto err_out_exit;
608
609                 dprintk("%s: st: %p, eng: %p, hash: %p, cipher: %p.\n",
610                                 __func__, st, &st->eng, &st->eng.hash, &st->eng.cipher);
611         }
612
613         for (i = 0; i < psb->crypto_thread_num; ++i) {
614                 err = -ENOMEM;
615                 t = kzalloc(sizeof(struct pohmelfs_crypto_thread), GFP_KERNEL);
616                 if (!t)
617                         goto err_out_free_state_engines;
618
619                 init_waitqueue_head(&t->wait);
620
621                 t->psb = psb;
622                 t->trans = NULL;
623                 t->eng.thread = t;
624
625                 err = pohmelfs_crypto_engine_init(&t->eng, psb);
626                 if (err)
627                         goto err_out_free_state_engines;
628
629                 err = pohmelfs_crypto_pages_alloc(&t->eng, psb);
630                 if (err)
631                         goto err_out_free;
632
633                 t->thread = kthread_run(pohmelfs_crypto_thread_func, t,
634                                 "pohmelfs-crypto-%d-%d", psb->idx, i);
635                 if (IS_ERR(t->thread)) {
636                         err = PTR_ERR(t->thread);
637                         t->thread = NULL;
638                         goto err_out_free;
639                 }
640
641                 if (t->eng.cipher)
642                         psb->crypto_align_size = crypto_ablkcipher_blocksize(t->eng.cipher);
643
644                 mutex_lock(&psb->crypto_thread_lock);
645                 list_add_tail(&t->thread_entry, &psb->crypto_ready_list);
646                 mutex_unlock(&psb->crypto_thread_lock);
647         }
648
649         psb->crypto_thread_num = i;
650         return 0;
651
652 err_out_free:
653         pohmelfs_sys_crypto_exit_one(t);
654 err_out_free_state_engines:
655         list_for_each_entry(c, &psb->state_list, config_entry) {
656                 st = &c->state;
657                 pohmelfs_crypto_engine_exit(&st->eng);
658         }
659 err_out_exit:
660         pohmelfs_sys_crypto_exit(psb);
661         return err;
662 }
663
664 void pohmelfs_crypto_exit(struct pohmelfs_sb *psb)
665 {
666         pohmelfs_sys_crypto_exit(psb);
667
668         kfree(psb->hash_string);
669         kfree(psb->cipher_string);
670 }
671
672 static int pohmelfs_crypt_init_complete(struct page **pages, unsigned int page_num,
673                 void *private, int err)
674 {
675         struct pohmelfs_sb *psb = private;
676
677         psb->flags = -err;
678         dprintk("%s: err: %d.\n", __func__, err);
679
680         wake_up(&psb->wait);
681
682         return err;
683 }
684
685 static int pohmelfs_crypto_init_handshake(struct pohmelfs_sb *psb)
686 {
687         struct netfs_trans *t;
688         struct netfs_crypto_capabilities *cap;
689         struct netfs_cmd *cmd;
690         char *str;
691         int err = -ENOMEM, size;
692
693         size = sizeof(struct netfs_crypto_capabilities) +
694                 psb->cipher_strlen + psb->hash_strlen + 2; /* 0 bytes */
695
696         t = netfs_trans_alloc(psb, size, 0, 0);
697         if (!t)
698                 goto err_out_exit;
699
700         t->complete = pohmelfs_crypt_init_complete;
701         t->private = psb;
702
703         cmd = netfs_trans_current(t);
704         cap = (struct netfs_crypto_capabilities *)(cmd + 1);
705         str = (char *)(cap + 1);
706
707         cmd->cmd = NETFS_CAPABILITIES;
708         cmd->id = POHMELFS_CRYPTO_CAPABILITIES;
709         cmd->size = size;
710         cmd->start = 0;
711         cmd->ext = 0;
712         cmd->csize = 0;
713
714         netfs_convert_cmd(cmd);
715         netfs_trans_update(cmd, t, size);
716
717         cap->hash_strlen = psb->hash_strlen;
718         if (cap->hash_strlen) {
719                 sprintf(str, "%s", psb->hash_string);
720                 str += cap->hash_strlen;
721         }
722
723         cap->cipher_strlen = psb->cipher_strlen;
724         cap->cipher_keysize = psb->cipher_keysize;
725         if (cap->cipher_strlen)
726                 sprintf(str, "%s", psb->cipher_string);
727
728         netfs_convert_crypto_capabilities(cap);
729
730         psb->flags = ~0;
731         err = netfs_trans_finish(t, psb);
732         if (err)
733                 goto err_out_exit;
734
735         err = wait_event_interruptible_timeout(psb->wait, (psb->flags != ~0),
736                         psb->wait_on_page_timeout);
737         if (!err)
738                 err = -ETIMEDOUT;
739         else if (err > 0)
740                 err = -psb->flags;
741
742         if (!err)
743                 psb->perform_crypto = 1;
744         psb->flags = 0;
745
746         /*
747          * At this point NETFS_CAPABILITIES response command
748          * should setup superblock in a way, which is acceptable
749          * for both client and server, so if server refuses connection,
750          * it will send error in transaction response.
751          */
752
753         if (err)
754                 goto err_out_exit;
755
756         return 0;
757
758 err_out_exit:
759         return err;
760 }
761
762 int pohmelfs_crypto_init(struct pohmelfs_sb *psb)
763 {
764         int err;
765
766         if (!psb->cipher_string && !psb->hash_string)
767                 return 0;
768
769         err = pohmelfs_crypto_init_handshake(psb);
770         if (err)
771                 return err;
772
773         err = pohmelfs_sys_crypto_init(psb);
774         if (err)
775                 return err;
776
777         return 0;
778 }
779
780 static int pohmelfs_crypto_thread_get(struct pohmelfs_sb *psb,
781                 int (*action)(struct pohmelfs_crypto_thread *t, void *data), void *data)
782 {
783         struct pohmelfs_crypto_thread *t = NULL;
784         int err;
785
786         while (!t) {
787                 err = wait_event_interruptible_timeout(psb->wait,
788                                 !list_empty(&psb->crypto_ready_list),
789                                 psb->wait_on_page_timeout);
790
791                 t = NULL;
792                 err = 0;
793                 mutex_lock(&psb->crypto_thread_lock);
794                 if (!list_empty(&psb->crypto_ready_list)) {
795                         t = list_entry(psb->crypto_ready_list.prev,
796                                         struct pohmelfs_crypto_thread,
797                                         thread_entry);
798
799                         list_move_tail(&t->thread_entry,
800                                         &psb->crypto_active_list);
801
802                         action(t, data);
803                         wake_up(&t->wait);
804
805                 }
806                 mutex_unlock(&psb->crypto_thread_lock);
807         }
808
809         return err;
810 }
811
812 static int pohmelfs_trans_crypt_action(struct pohmelfs_crypto_thread *t, void *data)
813 {
814         struct netfs_trans *trans = data;
815
816         netfs_trans_get(trans);
817         t->trans = trans;
818
819         dprintk("%s: t: %p, gen: %u, thread: %p.\n", __func__, trans, trans->gen, t);
820         return 0;
821 }
822
823 int pohmelfs_trans_crypt(struct netfs_trans *trans, struct pohmelfs_sb *psb)
824 {
825         if ((!psb->hash_string && !psb->cipher_string) || !psb->perform_crypto) {
826                 netfs_trans_get(trans);
827                 return pohmelfs_crypto_finish(trans, psb, 0);
828         }
829
830         return pohmelfs_crypto_thread_get(psb, pohmelfs_trans_crypt_action, trans);
831 }
832
833 struct pohmelfs_crypto_input_action_data {
834         struct page                     *page;
835         struct pohmelfs_crypto_engine   *e;
836         u64                             iv;
837         unsigned int                    size;
838 };
839
840 static int pohmelfs_crypt_input_page_action(struct pohmelfs_crypto_thread *t, void *data)
841 {
842         struct pohmelfs_crypto_input_action_data *act = data;
843
844         memcpy(t->eng.data, act->e->data, t->psb->crypto_attached_size);
845
846         t->size = act->size;
847         t->eng.iv = act->iv;
848
849         t->page = act->page;
850         return 0;
851 }
852
853 int pohmelfs_crypto_process_input_page(struct pohmelfs_crypto_engine *e,
854                 struct page *page, unsigned int size, u64 iv)
855 {
856         struct inode *inode = page->mapping->host;
857         struct pohmelfs_crypto_input_action_data act;
858         int err = -ENOENT;
859
860         act.page = page;
861         act.e = e;
862         act.size = size;
863         act.iv = iv;
864
865         err = pohmelfs_crypto_thread_get(POHMELFS_SB(inode->i_sb),
866                         pohmelfs_crypt_input_page_action, &act);
867         if (err)
868                 goto err_out_exit;
869
870         return 0;
871
872 err_out_exit:
873         SetPageUptodate(page);
874         page_cache_release(page);
875
876         return err;
877 }