linux/drivers/staging/pohmelfs/crypto.c
<<
>>
Prefs
   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}
 879