qemu/backends/cryptodev-lkcf.c
<<
>>
Prefs
   1/*
   2 * QEMU Cryptodev backend for QEMU cipher APIs
   3 *
   4 * Copyright (c) 2022 Bytedance.Inc
   5 *
   6 * Authors:
   7 *    lei he <helei.sig11@bytedance.com>
   8 *
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation; either
  12 * version 2.1 of the License, or (at your option) any later version.
  13 *
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  21 *
  22 */
  23
  24#include "qemu/osdep.h"
  25#include "crypto/cipher.h"
  26#include "crypto/akcipher.h"
  27#include "qapi/error.h"
  28#include "qemu/main-loop.h"
  29#include "qemu/thread.h"
  30#include "qemu/error-report.h"
  31#include "qemu/queue.h"
  32#include "qom/object.h"
  33#include "sysemu/cryptodev.h"
  34#include "standard-headers/linux/virtio_crypto.h"
  35
  36#include <keyutils.h>
  37#include <sys/eventfd.h>
  38
  39/**
  40 * @TYPE_CRYPTODEV_BACKEND_LKCF:
  41 * name of backend that uses linux kernel crypto framework
  42 */
  43#define TYPE_CRYPTODEV_BACKEND_LKCF "cryptodev-backend-lkcf"
  44
  45OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendLKCF, CRYPTODEV_BACKEND_LKCF)
  46
  47#define INVALID_KEY_ID -1
  48#define MAX_SESSIONS 256
  49#define NR_WORKER_THREAD 64
  50
  51#define KCTL_KEY_TYPE_PKEY "asymmetric"
  52/**
  53 * Here the key is uploaded to the thread-keyring of worker thread, at least
  54 * util linux-6.0:
  55 * 1. process keyring seems to behave unexpectedly if main-thread does not
  56 * create the keyring before creating any other thread.
  57 * 2. at present, the guest kernel never perform multiple operations on a
  58 * session.
  59 * 3. it can reduce the load of the main-loop because the key passed by the
  60 * guest kernel has been already checked.
  61 */
  62#define KCTL_KEY_RING KEY_SPEC_THREAD_KEYRING
  63
  64typedef struct CryptoDevBackendLKCFSession {
  65    uint8_t *key;
  66    size_t keylen;
  67    QCryptoAkCipherKeyType keytype;
  68    QCryptoAkCipherOptions akcipher_opts;
  69} CryptoDevBackendLKCFSession;
  70
  71typedef struct CryptoDevBackendLKCF CryptoDevBackendLKCF;
  72typedef struct CryptoDevLKCFTask CryptoDevLKCFTask;
  73struct CryptoDevLKCFTask {
  74    CryptoDevBackendLKCFSession *sess;
  75    CryptoDevBackendOpInfo *op_info;
  76    CryptoDevCompletionFunc cb;
  77    void *opaque;
  78    int status;
  79    CryptoDevBackendLKCF *lkcf;
  80    QSIMPLEQ_ENTRY(CryptoDevLKCFTask) queue;
  81};
  82
  83typedef struct CryptoDevBackendLKCF {
  84    CryptoDevBackend parent_obj;
  85    CryptoDevBackendLKCFSession *sess[MAX_SESSIONS];
  86    QSIMPLEQ_HEAD(, CryptoDevLKCFTask) requests;
  87    QSIMPLEQ_HEAD(, CryptoDevLKCFTask) responses;
  88    QemuMutex mutex;
  89    QemuCond cond;
  90    QemuMutex rsp_mutex;
  91
  92    /**
  93     * There is no async interface for asymmetric keys like AF_ALG sockets,
  94     * we don't seem to have better way than create a lots of thread.
  95     */
  96    QemuThread worker_threads[NR_WORKER_THREAD];
  97    bool running;
  98    int eventfd;
  99} CryptoDevBackendLKCF;
 100
 101static void *cryptodev_lkcf_worker(void *arg);
 102static int cryptodev_lkcf_close_session(CryptoDevBackend *backend,
 103                                        uint64_t session_id,
 104                                        uint32_t queue_index,
 105                                        CryptoDevCompletionFunc cb,
 106                                        void *opaque);
 107
 108static void cryptodev_lkcf_handle_response(void *opaque)
 109{
 110    CryptoDevBackendLKCF *lkcf = (CryptoDevBackendLKCF *)opaque;
 111    QSIMPLEQ_HEAD(, CryptoDevLKCFTask) responses;
 112    CryptoDevLKCFTask *task, *next;
 113    eventfd_t nevent;
 114
 115    QSIMPLEQ_INIT(&responses);
 116    eventfd_read(lkcf->eventfd, &nevent);
 117
 118    qemu_mutex_lock(&lkcf->rsp_mutex);
 119    QSIMPLEQ_PREPEND(&responses, &lkcf->responses);
 120    qemu_mutex_unlock(&lkcf->rsp_mutex);
 121
 122    QSIMPLEQ_FOREACH_SAFE(task, &responses, queue, next) {
 123        if (task->cb) {
 124            task->cb(task->opaque, task->status);
 125        }
 126        g_free(task);
 127    }
 128}
 129
 130static int cryptodev_lkcf_set_op_desc(QCryptoAkCipherOptions *opts,
 131                                      char *key_desc,
 132                                      size_t desc_len,
 133                                      Error **errp)
 134{
 135    QCryptoAkCipherOptionsRSA *rsa_opt;
 136    if (opts->alg != QCRYPTO_AKCIPHER_ALG_RSA) {
 137        error_setg(errp, "Unsupported alg: %u", opts->alg);
 138        return -1;
 139    }
 140
 141    rsa_opt = &opts->u.rsa;
 142    if (rsa_opt->padding_alg == QCRYPTO_RSA_PADDING_ALG_PKCS1) {
 143        snprintf(key_desc, desc_len, "enc=%s hash=%s",
 144                 QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg),
 145                 QCryptoHashAlgorithm_str(rsa_opt->hash_alg));
 146
 147    } else {
 148        snprintf(key_desc, desc_len, "enc=%s",
 149                 QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg));
 150    }
 151    return 0;
 152}
 153
 154static int cryptodev_lkcf_set_rsa_opt(int virtio_padding_alg,
 155                                      int virtio_hash_alg,
 156                                      QCryptoAkCipherOptionsRSA *opt,
 157                                      Error **errp)
 158{
 159    if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
 160        opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1;
 161
 162        switch (virtio_hash_alg) {
 163        case VIRTIO_CRYPTO_RSA_MD5:
 164            opt->hash_alg = QCRYPTO_HASH_ALG_MD5;
 165            break;
 166
 167        case VIRTIO_CRYPTO_RSA_SHA1:
 168            opt->hash_alg = QCRYPTO_HASH_ALG_SHA1;
 169            break;
 170
 171        case VIRTIO_CRYPTO_RSA_SHA256:
 172            opt->hash_alg = QCRYPTO_HASH_ALG_SHA256;
 173            break;
 174
 175        case VIRTIO_CRYPTO_RSA_SHA512:
 176            opt->hash_alg = QCRYPTO_HASH_ALG_SHA512;
 177            break;
 178
 179        default:
 180            error_setg(errp, "Unsupported rsa hash algo: %d", virtio_hash_alg);
 181            return -1;
 182        }
 183        return 0;
 184    }
 185
 186    if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
 187        opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
 188        return 0;
 189    }
 190
 191    error_setg(errp, "Unsupported rsa padding algo: %u", virtio_padding_alg);
 192    return -1;
 193}
 194
 195static int cryptodev_lkcf_get_unused_session_index(CryptoDevBackendLKCF *lkcf)
 196{
 197    size_t i;
 198
 199    for (i = 0; i < MAX_SESSIONS; i++) {
 200        if (lkcf->sess[i] == NULL) {
 201            return i;
 202        }
 203    }
 204    return -1;
 205}
 206
 207static void cryptodev_lkcf_init(CryptoDevBackend *backend, Error **errp)
 208{
 209    /* Only support one queue */
 210    int queues = backend->conf.peers.queues, i;
 211    CryptoDevBackendClient *cc;
 212    CryptoDevBackendLKCF *lkcf =
 213        CRYPTODEV_BACKEND_LKCF(backend);
 214
 215    if (queues != 1) {
 216        error_setg(errp,
 217                   "Only support one queue in cryptodev-builtin backend");
 218        return;
 219    }
 220    lkcf->eventfd = eventfd(0, 0);
 221    if (lkcf->eventfd < 0) {
 222        error_setg(errp, "Failed to create eventfd: %d", errno);
 223        return;
 224    }
 225
 226    cc = cryptodev_backend_new_client();
 227    cc->info_str = g_strdup_printf("cryptodev-lkcf0");
 228    cc->queue_index = 0;
 229    cc->type = QCRYPTODEV_BACKEND_TYPE_LKCF;
 230    backend->conf.peers.ccs[0] = cc;
 231
 232    backend->conf.crypto_services =
 233        1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER;
 234    backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
 235    lkcf->running = true;
 236
 237    QSIMPLEQ_INIT(&lkcf->requests);
 238    QSIMPLEQ_INIT(&lkcf->responses);
 239    qemu_mutex_init(&lkcf->mutex);
 240    qemu_mutex_init(&lkcf->rsp_mutex);
 241    qemu_cond_init(&lkcf->cond);
 242    for (i = 0; i < NR_WORKER_THREAD; i++) {
 243        qemu_thread_create(&lkcf->worker_threads[i], "lkcf-worker",
 244                           cryptodev_lkcf_worker, lkcf, 0);
 245    }
 246    qemu_set_fd_handler(
 247        lkcf->eventfd, cryptodev_lkcf_handle_response, NULL, lkcf);
 248    cryptodev_backend_set_ready(backend, true);
 249}
 250
 251static void cryptodev_lkcf_cleanup(CryptoDevBackend *backend, Error **errp)
 252{
 253    CryptoDevBackendLKCF *lkcf = CRYPTODEV_BACKEND_LKCF(backend);
 254    size_t i;
 255    int queues = backend->conf.peers.queues;
 256    CryptoDevBackendClient *cc;
 257    CryptoDevLKCFTask *task, *next;
 258
 259    qemu_mutex_lock(&lkcf->mutex);
 260    lkcf->running = false;
 261    qemu_mutex_unlock(&lkcf->mutex);
 262    qemu_cond_broadcast(&lkcf->cond);
 263
 264    close(lkcf->eventfd);
 265    for (i = 0; i < NR_WORKER_THREAD; i++) {
 266        qemu_thread_join(&lkcf->worker_threads[i]);
 267    }
 268
 269    QSIMPLEQ_FOREACH_SAFE(task, &lkcf->requests, queue, next) {
 270        if (task->cb) {
 271            task->cb(task->opaque, task->status);
 272        }
 273        g_free(task);
 274    }
 275
 276    QSIMPLEQ_FOREACH_SAFE(task, &lkcf->responses, queue, next) {
 277        if (task->cb) {
 278            task->cb(task->opaque, task->status);
 279        }
 280        g_free(task);
 281    }
 282
 283    qemu_mutex_destroy(&lkcf->mutex);
 284    qemu_cond_destroy(&lkcf->cond);
 285    qemu_mutex_destroy(&lkcf->rsp_mutex);
 286
 287    for (i = 0; i < MAX_SESSIONS; i++) {
 288        if (lkcf->sess[i] != NULL) {
 289            cryptodev_lkcf_close_session(backend, i, 0, NULL, NULL);
 290        }
 291    }
 292
 293    for (i = 0; i < queues; i++) {
 294        cc = backend->conf.peers.ccs[i];
 295        if (cc) {
 296            cryptodev_backend_free_client(cc);
 297            backend->conf.peers.ccs[i] = NULL;
 298        }
 299    }
 300
 301    cryptodev_backend_set_ready(backend, false);
 302}
 303
 304static void cryptodev_lkcf_execute_task(CryptoDevLKCFTask *task)
 305{
 306    CryptoDevBackendLKCFSession *session = task->sess;
 307    CryptoDevBackendAsymOpInfo *asym_op_info;
 308    bool kick = false;
 309    int ret, status, op_code = task->op_info->op_code;
 310    size_t p8info_len;
 311    g_autofree uint8_t *p8info = NULL;
 312    Error *local_error = NULL;
 313    key_serial_t key_id = INVALID_KEY_ID;
 314    char op_desc[64];
 315    g_autoptr(QCryptoAkCipher) akcipher = NULL;
 316
 317    /**
 318     * We only offload private key session:
 319     * 1. currently, the Linux kernel can only accept public key wrapped
 320     * with X.509 certificates, but unfortunately the cost of making a
 321     * ceritificate with public key is too expensive.
 322     * 2. generally, public key related compution is fast, just compute it with
 323     * thread-pool.
 324     */
 325    if (session->keytype == QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE) {
 326        if (qcrypto_akcipher_export_p8info(&session->akcipher_opts,
 327                                           session->key, session->keylen,
 328                                           &p8info, &p8info_len,
 329                                           &local_error) != 0 ||
 330            cryptodev_lkcf_set_op_desc(&session->akcipher_opts, op_desc,
 331                                       sizeof(op_desc), &local_error) != 0) {
 332            error_report_err(local_error);
 333        } else {
 334            key_id = add_key(KCTL_KEY_TYPE_PKEY, "lkcf-backend-priv-key",
 335                             p8info, p8info_len, KCTL_KEY_RING);
 336        }
 337    }
 338
 339    if (key_id < 0) {
 340        if (!qcrypto_akcipher_supports(&session->akcipher_opts)) {
 341            status = -VIRTIO_CRYPTO_NOTSUPP;
 342            goto out;
 343        }
 344        akcipher = qcrypto_akcipher_new(&session->akcipher_opts,
 345                                        session->keytype,
 346                                        session->key, session->keylen,
 347                                        &local_error);
 348        if (!akcipher) {
 349            status = -VIRTIO_CRYPTO_ERR;
 350            goto out;
 351        }
 352    }
 353
 354    asym_op_info = task->op_info->u.asym_op_info;
 355    switch (op_code) {
 356    case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
 357        if (key_id >= 0) {
 358            ret = keyctl_pkey_encrypt(key_id, op_desc,
 359                asym_op_info->src, asym_op_info->src_len,
 360                asym_op_info->dst, asym_op_info->dst_len);
 361        } else {
 362            ret = qcrypto_akcipher_encrypt(akcipher,
 363                asym_op_info->src, asym_op_info->src_len,
 364                asym_op_info->dst, asym_op_info->dst_len, &local_error);
 365        }
 366        break;
 367
 368    case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
 369        if (key_id >= 0) {
 370            ret = keyctl_pkey_decrypt(key_id, op_desc,
 371                asym_op_info->src, asym_op_info->src_len,
 372                asym_op_info->dst, asym_op_info->dst_len);
 373        } else {
 374            ret = qcrypto_akcipher_decrypt(akcipher,
 375                asym_op_info->src, asym_op_info->src_len,
 376                asym_op_info->dst, asym_op_info->dst_len, &local_error);
 377        }
 378        break;
 379
 380    case VIRTIO_CRYPTO_AKCIPHER_SIGN:
 381        if (key_id >= 0) {
 382            ret = keyctl_pkey_sign(key_id, op_desc,
 383                asym_op_info->src, asym_op_info->src_len,
 384                asym_op_info->dst, asym_op_info->dst_len);
 385        } else {
 386            ret = qcrypto_akcipher_sign(akcipher,
 387                asym_op_info->src, asym_op_info->src_len,
 388                asym_op_info->dst, asym_op_info->dst_len, &local_error);
 389        }
 390        break;
 391
 392    case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
 393        if (key_id >= 0) {
 394            ret = keyctl_pkey_verify(key_id, op_desc,
 395                asym_op_info->src, asym_op_info->src_len,
 396                asym_op_info->dst, asym_op_info->dst_len);
 397        } else {
 398            ret = qcrypto_akcipher_verify(akcipher,
 399                asym_op_info->src, asym_op_info->src_len,
 400                asym_op_info->dst, asym_op_info->dst_len, &local_error);
 401        }
 402        break;
 403
 404    default:
 405        error_setg(&local_error, "Unknown opcode: %u", op_code);
 406        status = -VIRTIO_CRYPTO_ERR;
 407        goto out;
 408    }
 409
 410    if (ret < 0) {
 411        if (!local_error) {
 412            if (errno != EKEYREJECTED) {
 413                error_report("Failed do operation with keyctl: %d", errno);
 414            }
 415        } else {
 416            error_report_err(local_error);
 417        }
 418        status = op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY ?
 419            -VIRTIO_CRYPTO_KEY_REJECTED : -VIRTIO_CRYPTO_ERR;
 420    } else {
 421        status = VIRTIO_CRYPTO_OK;
 422        asym_op_info->dst_len = ret;
 423    }
 424
 425out:
 426    if (key_id >= 0) {
 427        keyctl_unlink(key_id, KCTL_KEY_RING);
 428    }
 429    task->status = status;
 430
 431    qemu_mutex_lock(&task->lkcf->rsp_mutex);
 432    if (QSIMPLEQ_EMPTY(&task->lkcf->responses)) {
 433        kick = true;
 434    }
 435    QSIMPLEQ_INSERT_TAIL(&task->lkcf->responses, task, queue);
 436    qemu_mutex_unlock(&task->lkcf->rsp_mutex);
 437
 438    if (kick) {
 439        eventfd_write(task->lkcf->eventfd, 1);
 440    }
 441}
 442
 443static void *cryptodev_lkcf_worker(void *arg)
 444{
 445    CryptoDevBackendLKCF *backend = (CryptoDevBackendLKCF *)arg;
 446    CryptoDevLKCFTask *task;
 447
 448    for (;;) {
 449        task = NULL;
 450        qemu_mutex_lock(&backend->mutex);
 451        while (backend->running && QSIMPLEQ_EMPTY(&backend->requests)) {
 452            qemu_cond_wait(&backend->cond, &backend->mutex);
 453        }
 454        if (backend->running) {
 455            task = QSIMPLEQ_FIRST(&backend->requests);
 456            QSIMPLEQ_REMOVE_HEAD(&backend->requests, queue);
 457        }
 458        qemu_mutex_unlock(&backend->mutex);
 459
 460        /* stopped */
 461        if (!task) {
 462            break;
 463        }
 464        cryptodev_lkcf_execute_task(task);
 465   }
 466
 467   return NULL;
 468}
 469
 470static int cryptodev_lkcf_operation(
 471    CryptoDevBackend *backend,
 472    CryptoDevBackendOpInfo *op_info)
 473{
 474    CryptoDevBackendLKCF *lkcf =
 475        CRYPTODEV_BACKEND_LKCF(backend);
 476    CryptoDevBackendLKCFSession *sess;
 477    QCryptodevBackendAlgType algtype = op_info->algtype;
 478    CryptoDevLKCFTask *task;
 479
 480    if (op_info->session_id >= MAX_SESSIONS ||
 481        lkcf->sess[op_info->session_id] == NULL) {
 482        error_report("Cannot find a valid session id: %" PRIu64 "",
 483                     op_info->session_id);
 484        return -VIRTIO_CRYPTO_INVSESS;
 485    }
 486
 487    sess = lkcf->sess[op_info->session_id];
 488    if (algtype != QCRYPTODEV_BACKEND_ALG_ASYM) {
 489        error_report("algtype not supported: %u", algtype);
 490        return -VIRTIO_CRYPTO_NOTSUPP;
 491    }
 492
 493    task = g_new0(CryptoDevLKCFTask, 1);
 494    task->op_info = op_info;
 495    task->cb = op_info->cb;
 496    task->opaque = op_info->opaque;
 497    task->sess = sess;
 498    task->lkcf = lkcf;
 499    task->status = -VIRTIO_CRYPTO_ERR;
 500
 501    qemu_mutex_lock(&lkcf->mutex);
 502    QSIMPLEQ_INSERT_TAIL(&lkcf->requests, task, queue);
 503    qemu_mutex_unlock(&lkcf->mutex);
 504    qemu_cond_signal(&lkcf->cond);
 505
 506    return VIRTIO_CRYPTO_OK;
 507}
 508
 509static int cryptodev_lkcf_create_asym_session(
 510    CryptoDevBackendLKCF *lkcf,
 511    CryptoDevBackendAsymSessionInfo *sess_info,
 512    uint64_t *session_id)
 513{
 514    Error *local_error = NULL;
 515    int index;
 516    g_autofree CryptoDevBackendLKCFSession *sess =
 517        g_new0(CryptoDevBackendLKCFSession, 1);
 518
 519    switch (sess_info->algo) {
 520    case VIRTIO_CRYPTO_AKCIPHER_RSA:
 521        sess->akcipher_opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
 522        if (cryptodev_lkcf_set_rsa_opt(
 523            sess_info->u.rsa.padding_algo, sess_info->u.rsa.hash_algo,
 524            &sess->akcipher_opts.u.rsa, &local_error) != 0) {
 525            error_report_err(local_error);
 526            return -VIRTIO_CRYPTO_ERR;
 527        }
 528        break;
 529
 530    default:
 531        error_report("Unsupported asym alg %u", sess_info->algo);
 532        return -VIRTIO_CRYPTO_NOTSUPP;
 533    }
 534
 535    switch (sess_info->keytype) {
 536    case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
 537        sess->keytype = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
 538        break;
 539
 540    case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
 541        sess->keytype = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
 542        break;
 543
 544    default:
 545        error_report("Unknown akcipher keytype: %u", sess_info->keytype);
 546        return -VIRTIO_CRYPTO_ERR;
 547    }
 548
 549    index = cryptodev_lkcf_get_unused_session_index(lkcf);
 550    if (index < 0) {
 551        error_report("Total number of sessions created exceeds %u",
 552                     MAX_SESSIONS);
 553        return -VIRTIO_CRYPTO_ERR;
 554    }
 555
 556    sess->keylen = sess_info->keylen;
 557    sess->key = g_malloc(sess_info->keylen);
 558    memcpy(sess->key, sess_info->key, sess_info->keylen);
 559
 560    lkcf->sess[index] = g_steal_pointer(&sess);
 561    *session_id = index;
 562
 563    return VIRTIO_CRYPTO_OK;
 564}
 565
 566static int cryptodev_lkcf_create_session(
 567    CryptoDevBackend *backend,
 568    CryptoDevBackendSessionInfo *sess_info,
 569    uint32_t queue_index,
 570    CryptoDevCompletionFunc cb,
 571    void *opaque)
 572{
 573    CryptoDevBackendAsymSessionInfo *asym_sess_info;
 574    CryptoDevBackendLKCF *lkcf =
 575        CRYPTODEV_BACKEND_LKCF(backend);
 576    int ret;
 577
 578    switch (sess_info->op_code) {
 579    case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
 580        asym_sess_info = &sess_info->u.asym_sess_info;
 581        ret = cryptodev_lkcf_create_asym_session(
 582            lkcf, asym_sess_info, &sess_info->session_id);
 583        break;
 584
 585    default:
 586        ret = -VIRTIO_CRYPTO_NOTSUPP;
 587        error_report("Unsupported opcode: %" PRIu32 "",
 588                     sess_info->op_code);
 589        break;
 590    }
 591    if (cb) {
 592        cb(opaque, ret);
 593    }
 594    return 0;
 595}
 596
 597static int cryptodev_lkcf_close_session(CryptoDevBackend *backend,
 598                                        uint64_t session_id,
 599                                        uint32_t queue_index,
 600                                        CryptoDevCompletionFunc cb,
 601                                        void *opaque)
 602{
 603    CryptoDevBackendLKCF *lkcf = CRYPTODEV_BACKEND_LKCF(backend);
 604    CryptoDevBackendLKCFSession *session;
 605
 606    assert(session_id < MAX_SESSIONS && lkcf->sess[session_id]);
 607    session = lkcf->sess[session_id];
 608    lkcf->sess[session_id] = NULL;
 609
 610    g_free(session->key);
 611    g_free(session);
 612
 613    if (cb) {
 614        cb(opaque, VIRTIO_CRYPTO_OK);
 615    }
 616    return 0;
 617}
 618
 619static void cryptodev_lkcf_class_init(ObjectClass *oc, void *data)
 620{
 621    CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
 622
 623    bc->init = cryptodev_lkcf_init;
 624    bc->cleanup = cryptodev_lkcf_cleanup;
 625    bc->create_session = cryptodev_lkcf_create_session;
 626    bc->close_session = cryptodev_lkcf_close_session;
 627    bc->do_op = cryptodev_lkcf_operation;
 628}
 629
 630static const TypeInfo cryptodev_builtin_info = {
 631    .name = TYPE_CRYPTODEV_BACKEND_LKCF,
 632    .parent = TYPE_CRYPTODEV_BACKEND,
 633    .class_init = cryptodev_lkcf_class_init,
 634    .instance_size = sizeof(CryptoDevBackendLKCF),
 635};
 636
 637static void cryptodev_lkcf_register_types(void)
 638{
 639    type_register_static(&cryptodev_builtin_info);
 640}
 641
 642type_init(cryptodev_lkcf_register_types);
 643