Linux Audio

Check our new training course

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