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