diff mbox

[v1,11/14] virtio-crypto: add control queue handler

Message ID 1473306156-176628-12-git-send-email-arei.gonglei@huawei.com (mailing list archive)
State New, archived
Headers show

Commit Message

Gonglei (Arei) Sept. 8, 2016, 3:42 a.m. UTC
Realize the Symmetric algos session creation handler,
including plain cipher and chainning algorithms.

Signed-off-by: Gonglei <arei.gonglei@huawei.com>
---
 hw/virtio/virtio-crypto.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 172 insertions(+)

Comments

Michael S. Tsirkin Sept. 8, 2016, 4:30 a.m. UTC | #1
On Thu, Sep 08, 2016 at 11:42:33AM +0800, Gonglei wrote:
> +    info->cipher_alg = virtio_ldl_p(vdev, &cipher_para->algo);
> +    info->key_len = virtio_ldl_p(vdev, &cipher_para->keylen);
> +    info->direction = virtio_ldl_p(vdev, &cipher_para->op);

There is no reason to use the virtio mixed endian-ness for
modern devices. Just use little-endian everywhere.
Gonglei (Arei) Sept. 8, 2016, 4:58 a.m. UTC | #2
> -----Original Message-----
> From: virtio-dev@lists.oasis-open.org [mailto:virtio-dev@lists.oasis-open.org]
> On Behalf Of Michael S. Tsirkin
> Sent: Thursday, September 08, 2016 12:30 PM
> To: Gonglei (Arei)
> Subject: [virtio-dev] Re: [PATCH v1 11/14] virtio-crypto: add control queue
> handler
> 
> On Thu, Sep 08, 2016 at 11:42:33AM +0800, Gonglei wrote:
> > +    info->cipher_alg = virtio_ldl_p(vdev, &cipher_para->algo);
> > +    info->key_len = virtio_ldl_p(vdev, &cipher_para->keylen);
> > +    info->direction = virtio_ldl_p(vdev, &cipher_para->op);
> 
> There is no reason to use the virtio mixed endian-ness for
> modern devices. Just use little-endian everywhere.
> 
Okay, thanks :)


Regards,
-Gonglei
diff mbox

Patch

diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index b7a7b41..b3ad974 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -26,8 +26,180 @@  static void virtio_crypto_process(VirtIOCrypto *vcrypto)
 {
 }
 
+static inline int virtio_crypto_vq2q(int queue_index)
+{
+    return queue_index;
+}
+
+static void
+virtio_crypto_cipher_session_helper(VirtIODevice *vdev,
+           CryptoSymSessionInfo *info,
+           struct virtio_crypto_cipher_session_para *cipher_para,
+           struct virtio_crypto_cipher_session_output *cipher_out)
+{
+    hwaddr key_gpa;
+    void *key_hva;
+    hwaddr len;
+
+    info->cipher_alg = virtio_ldl_p(vdev, &cipher_para->algo);
+    info->key_len = virtio_ldl_p(vdev, &cipher_para->keylen);
+    info->direction = virtio_ldl_p(vdev, &cipher_para->op);
+    len = info->key_len;
+    /* get cipher key */
+    if (len > 0) {
+        DPRINTF("keylen=%" PRIu32 "\n", info->key_len);
+        key_gpa = virtio_ldq_p(vdev, &cipher_out->key_addr);
+
+        key_hva = cpu_physical_memory_map(key_gpa, &len, 0);
+
+        info->cipher_key = g_malloc(info->key_len);
+        memcpy(info->cipher_key, key_hva, info->key_len);
+        cpu_physical_memory_unmap(key_hva, len, 0, len);
+    }
+}
+
+static int64_t
+virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
+               struct virtio_crypto_sym_create_session_req *sess_req,
+               uint32_t queue_id,
+               uint64_t *session_id)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+    CryptoSymSessionInfo info;
+    int ret;
+    CryptoClientState *cc;
+    int queue_index;;
+    uint32_t op_type;
+    hwaddr auth_key_gpa;
+    void *auth_key_hva;
+    struct virtio_crypto_session_input *input;
+    hwaddr len;
+
+    op_type = virtio_ldl_p(vdev, &sess_req->op_type);
+    info.op_type = op_type;
+
+    if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) {
+        virtio_crypto_cipher_session_helper(vdev, &info,
+                           &sess_req->u.cipher.para,
+                           &sess_req->u.cipher.out);
+        input = &sess_req->u.cipher.input;
+    } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
+        /* cipher part */
+        virtio_crypto_cipher_session_helper(vdev, &info,
+                           &sess_req->u.chain.para.cipher_param,
+                           &sess_req->u.chain.out.cipher);
+        input = &sess_req->u.chain.input;
+        /* hash part */
+        info.alg_chain_order = virtio_ldl_p(vdev,
+                               &sess_req->u.chain.para.alg_chain_order);
+        info.add_len = virtio_ldl_p(vdev,
+                               &sess_req->u.chain.para.aad_len);
+        info.hash_mode = virtio_ldl_p(vdev, &sess_req->u.chain.para.hash_mode);
+        if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) {
+            info.hash_alg = virtio_ldl_p(vdev,
+                              &sess_req->u.chain.para.u.mac_param.algo);
+            len = info.auth_key_len = virtio_ldl_p(vdev,
+                              &sess_req->u.chain.para.u.mac_param.auth_key_len);
+            info.hash_result_len = virtio_ldl_p(vdev,
+                       &sess_req->u.chain.para.u.mac_param.hash_result_len);
+            /* get auth key */
+            if (len > 0) {
+                DPRINTF("keylen=%" PRIu32 "\n", info.auth_key_len);
+                auth_key_gpa = virtio_ldq_p(vdev,
+                               &sess_req->u.chain.out.mac.auth_key_addr);
+                auth_key_hva = cpu_physical_memory_map(auth_key_gpa,
+                               &len, false);
+                info.auth_key = g_malloc(len);
+                memcpy(info.auth_key, auth_key_hva, len);
+                cpu_physical_memory_unmap(auth_key_hva, len, false, len);
+            }
+        } else if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) {
+            info.hash_alg = virtio_ldl_p(vdev,
+                              &sess_req->u.chain.para.u.hash_param.algo);
+            info.hash_result_len = virtio_ldl_p(vdev,
+                     &sess_req->u.chain.para.u.hash_param.hash_result_len);
+        } else {
+            /* VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED */
+            error_report("unsupported hash mode");
+            goto err;
+        }
+    } else {
+        /* VIRTIO_CRYPTO_SYM_OP_NONE */
+        error_report("unsupported cipher type");
+        goto err;
+    }
+
+    queue_index = virtio_crypto_vq2q(queue_id);
+    cc = qemu_get_crypto_subqueue(vcrypto->crypto, queue_index);
+    ret = qemu_crypto_create_session(cc, &info, session_id);
+    if (ret == 0) {
+        DPRINTF("create session_id=%" PRIu64 "\n", *session_id);
+        /* Set the result, notify the frontend driver soon */
+        virtio_stl_p(vdev, &input->status, VIRTIO_CRYPTO_OP_OK);
+        virtio_stq_p(vdev, &input->session_id, *session_id);
+        return 0;
+    }
+
+err:
+    virtio_stl_p(vdev, &input->status, VIRTIO_CRYPTO_OP_ERR);
+    return -1;
+}
+
 static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
 {
+    VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
+    struct virtio_crypto_op_ctrl_req ctrl;
+    VirtQueueElement *elem;
+    size_t s;
+    struct iovec *iov;
+    unsigned int iov_cnt;
+    uint32_t queue_id;
+    uint32_t opcode;
+    uint64_t session_id = 0;
+
+    for (;;) {
+        elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+        if (!elem) {
+            break;
+        }
+        if (elem->in_num < 1 ||
+            iov_size(elem->in_sg, elem->in_num) < sizeof(ctrl)) {
+            error_report("virtio-crypto ctrl missing headers");
+            exit(1);
+        }
+
+        iov_cnt = elem->in_num;
+        iov = elem->in_sg;
+        s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl));
+        assert(s == sizeof(ctrl));
+        opcode = virtio_ldl_p(vdev, &ctrl.header.opcode);
+        queue_id = virtio_ldl_p(vdev, &ctrl.header.queue_id);
+
+        switch (opcode) {
+        case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
+            virtio_crypto_create_sym_session(vcrypto,
+                             &ctrl.u.sym_create_session,
+                             queue_id,
+                             &session_id);
+
+            break;
+        case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION:
+        case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
+        case VIRTIO_CRYPTO_HASH_DESTROY_SESSION:
+        case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
+        case VIRTIO_CRYPTO_MAC_DESTROY_SESSION:
+        case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
+        case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION:
+        default:
+            error_report("virtio-crypto unsupported ctrl opcode: %u",
+                         opcode);
+            exit(1);
+        }
+
+        virtqueue_push(vq, elem, sizeof(ctrl));
+        virtio_notify(vdev, vq);
+        g_free(elem);
+    }
 }
 
 static void virtio_crypto_handle_dataq_bh(VirtIODevice *vdev, VirtQueue *vq)