Beispiel #1
0
static int
virtio_crypto_handle_request(VirtIOCryptoReq *request)
{
    VirtIOCrypto *vcrypto = request->vcrypto;
    VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
    VirtQueueElement *elem = &request->elem;
    int queue_index = virtio_crypto_vq2q(virtio_get_queue_index(request->vq));
    struct virtio_crypto_op_data_req req;
    int ret;
    struct iovec *in_iov;
    struct iovec *out_iov;
    unsigned in_num;
    unsigned out_num;
    uint32_t opcode;
    uint8_t status = VIRTIO_CRYPTO_ERR;
    uint64_t session_id;
    CryptoDevBackendSymOpInfo *sym_op_info = NULL;
    Error *local_err = NULL;

    if (elem->out_num < 1 || elem->in_num < 1) {
        virtio_error(vdev, "virtio-crypto dataq missing headers");
        return -1;
    }

    out_num = elem->out_num;
    out_iov = elem->out_sg;
    in_num = elem->in_num;
    in_iov = elem->in_sg;
    if (unlikely(iov_to_buf(out_iov, out_num, 0, &req, sizeof(req))
                != sizeof(req))) {
        virtio_error(vdev, "virtio-crypto request outhdr too short");
        return -1;
    }
    iov_discard_front(&out_iov, &out_num, sizeof(req));

    if (in_iov[in_num - 1].iov_len <
            sizeof(struct virtio_crypto_inhdr)) {
        virtio_error(vdev, "virtio-crypto request inhdr too short");
        return -1;
    }
    /* We always touch the last byte, so just see how big in_iov is. */
    request->in_len = iov_size(in_iov, in_num);
    request->in = (void *)in_iov[in_num - 1].iov_base
              + in_iov[in_num - 1].iov_len
              - sizeof(struct virtio_crypto_inhdr);
    iov_discard_back(in_iov, &in_num, sizeof(struct virtio_crypto_inhdr));

    /*
     * The length of operation result, including dest_data
     * and digest_result if exists.
     */
    request->in_num = in_num;
    request->in_iov = in_iov;

    opcode = ldl_le_p(&req.header.opcode);
    session_id = ldq_le_p(&req.header.session_id);

    switch (opcode) {
    case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
    case VIRTIO_CRYPTO_CIPHER_DECRYPT:
        ret = virtio_crypto_handle_sym_req(vcrypto,
                         &req.u.sym_req,
                         &sym_op_info,
                         out_iov, out_num);
        /* Serious errors, need to reset virtio crypto device */
        if (ret == -EFAULT) {
            return -1;
        } else if (ret == -VIRTIO_CRYPTO_NOTSUPP) {
            virtio_crypto_req_complete(request, VIRTIO_CRYPTO_NOTSUPP);
            virtio_crypto_free_request(request);
        } else {
            sym_op_info->session_id = session_id;

            /* Set request's parameter */
            request->flags = CRYPTODEV_BACKEND_ALG_SYM;
            request->u.sym_op_info = sym_op_info;
            ret = cryptodev_backend_crypto_operation(vcrypto->cryptodev,
                                    request, queue_index, &local_err);
            if (ret < 0) {
                status = -ret;
                if (local_err) {
                    error_report_err(local_err);
                }
            } else { /* ret == VIRTIO_CRYPTO_OK */
                status = ret;
            }
            virtio_crypto_req_complete(request, status);
            virtio_crypto_free_request(request);
        }
        break;
    case VIRTIO_CRYPTO_HASH:
    case VIRTIO_CRYPTO_MAC:
    case VIRTIO_CRYPTO_AEAD_ENCRYPT:
    case VIRTIO_CRYPTO_AEAD_DECRYPT:
    default:
        error_report("virtio-crypto unsupported dataq opcode: %u",
                     opcode);
        virtio_crypto_req_complete(request, VIRTIO_CRYPTO_NOTSUPP);
        virtio_crypto_free_request(request);
    }

    return 0;
}
Beispiel #2
0
void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
{
    uint32_t type;
    struct iovec *in_iov = req->elem->in_sg;
    struct iovec *iov = req->elem->out_sg;
    unsigned in_num = req->elem->in_num;
    unsigned out_num = req->elem->out_num;

    if (req->elem->out_num < 1 || req->elem->in_num < 1) {
        error_report("virtio-blk missing headers");
        exit(1);
    }

    if (unlikely(iov_to_buf(iov, out_num, 0, &req->out,
                            sizeof(req->out)) != sizeof(req->out))) {
        error_report("virtio-blk request outhdr too short");
        exit(1);
    }

    iov_discard_front(&iov, &out_num, sizeof(req->out));

    if (in_num < 1 ||
        in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) {
        error_report("virtio-blk request inhdr too short");
        exit(1);
    }

    req->in = (void *)in_iov[in_num - 1].iov_base
              + in_iov[in_num - 1].iov_len
              - sizeof(struct virtio_blk_inhdr);
    iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr));

    type = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);

    if (type & VIRTIO_BLK_T_FLUSH) {
        virtio_blk_handle_flush(req, mrb);
    } else if (type & VIRTIO_BLK_T_SCSI_CMD) {
        virtio_blk_handle_scsi(req);
    } else if (type & VIRTIO_BLK_T_GET_ID) {
        VirtIOBlock *s = req->dev;

        /*
         * NB: per existing s/n string convention the string is
         * terminated by '\0' only when shorter than buffer.
         */
        strncpy(req->elem->in_sg[0].iov_base,
                s->blk.serial ? s->blk.serial : "",
                MIN(req->elem->in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
        virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
        virtio_blk_free_request(req);
    } else if (type & VIRTIO_BLK_T_OUT) {
        qemu_iovec_init_external(&req->qiov, &req->elem->out_sg[1],
                                 req->elem->out_num - 1);
        virtio_blk_handle_write(req, mrb);
    } else if (type == VIRTIO_BLK_T_IN || type == VIRTIO_BLK_T_BARRIER) {
        /* VIRTIO_BLK_T_IN is 0, so we can't just & it. */
        qemu_iovec_init_external(&req->qiov, &req->elem->in_sg[0],
                                 req->elem->in_num - 1);
        virtio_blk_handle_read(req);
    } else {
        virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
        virtio_blk_free_request(req);
    }
}
Beispiel #3
0
static void test_discard_back(void)
{
    struct iovec *iov;
    unsigned int iov_cnt;
    unsigned int iov_cnt_tmp;
    void *old_base;
    size_t size;
    size_t ret;

    /* Discard zero bytes */
    iov_random(&iov, &iov_cnt);
    iov_cnt_tmp = iov_cnt;
    ret = iov_discard_back(iov, &iov_cnt_tmp, 0);
    g_assert(ret == 0);
    g_assert(iov_cnt_tmp == iov_cnt);
    iov_free(iov, iov_cnt);

    /* Discard more bytes than vector size */
    iov_random(&iov, &iov_cnt);
    iov_cnt_tmp = iov_cnt;
    size = iov_size(iov, iov_cnt);
    ret = iov_discard_back(iov, &iov_cnt_tmp, size + 1);
    g_assert(ret == size);
    g_assert(iov_cnt_tmp == 0);
    iov_free(iov, iov_cnt);

    /* Discard entire vector */
    iov_random(&iov, &iov_cnt);
    iov_cnt_tmp = iov_cnt;
    size = iov_size(iov, iov_cnt);
    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
    g_assert(ret == size);
    g_assert(iov_cnt_tmp == 0);
    iov_free(iov, iov_cnt);

    /* Discard within last element */
    iov_random(&iov, &iov_cnt);
    iov_cnt_tmp = iov_cnt;
    old_base = iov[iov_cnt - 1].iov_base;
    size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
    g_assert(ret == size);
    g_assert(iov_cnt_tmp == iov_cnt);
    g_assert(iov[iov_cnt - 1].iov_base == old_base);
    iov_free(iov, iov_cnt);

    /* Discard entire last element */
    iov_random(&iov, &iov_cnt);
    iov_cnt_tmp = iov_cnt;
    old_base = iov[iov_cnt - 1].iov_base;
    size = iov[iov_cnt - 1].iov_len;
    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
    g_assert(ret == size);
    g_assert(iov_cnt_tmp == iov_cnt - 1);
    iov_free(iov, iov_cnt);

    /* Discard within second-to-last element */
    iov_random(&iov, &iov_cnt);
    iov_cnt_tmp = iov_cnt;
    old_base = iov[iov_cnt - 2].iov_base;
    size = iov[iov_cnt - 1].iov_len +
           g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
    g_assert(ret == size);
    g_assert(iov_cnt_tmp == iov_cnt - 1);
    g_assert(iov[iov_cnt - 2].iov_base == old_base);
    iov_free(iov, iov_cnt);
}