18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci /* Algorithms supported by virtio crypto device 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Authors: Gonglei <arei.gonglei@huawei.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 108c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 118c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 148c2ecf20Sopenharmony_ci#include <linux/atomic.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <uapi/linux/virtio_crypto.h> 178c2ecf20Sopenharmony_ci#include "virtio_crypto_common.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct virtio_crypto_skcipher_ctx { 218c2ecf20Sopenharmony_ci struct crypto_engine_ctx enginectx; 228c2ecf20Sopenharmony_ci struct virtio_crypto *vcrypto; 238c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci struct virtio_crypto_sym_session_info enc_sess_info; 268c2ecf20Sopenharmony_ci struct virtio_crypto_sym_session_info dec_sess_info; 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct virtio_crypto_sym_request { 308c2ecf20Sopenharmony_ci struct virtio_crypto_request base; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci /* Cipher or aead */ 338c2ecf20Sopenharmony_ci uint32_t type; 348c2ecf20Sopenharmony_ci struct virtio_crypto_skcipher_ctx *skcipher_ctx; 358c2ecf20Sopenharmony_ci struct skcipher_request *skcipher_req; 368c2ecf20Sopenharmony_ci uint8_t *iv; 378c2ecf20Sopenharmony_ci /* Encryption? */ 388c2ecf20Sopenharmony_ci bool encrypt; 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistruct virtio_crypto_algo { 428c2ecf20Sopenharmony_ci uint32_t algonum; 438c2ecf20Sopenharmony_ci uint32_t service; 448c2ecf20Sopenharmony_ci unsigned int active_devs; 458c2ecf20Sopenharmony_ci struct skcipher_alg algo; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * The algs_lock protects the below global virtio_crypto_active_devs 508c2ecf20Sopenharmony_ci * and crypto algorithms registion. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(algs_lock); 538c2ecf20Sopenharmony_cistatic void virtio_crypto_skcipher_finalize_req( 548c2ecf20Sopenharmony_ci struct virtio_crypto_sym_request *vc_sym_req, 558c2ecf20Sopenharmony_ci struct skcipher_request *req, 568c2ecf20Sopenharmony_ci int err); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void virtio_crypto_dataq_sym_callback 598c2ecf20Sopenharmony_ci (struct virtio_crypto_request *vc_req, int len) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct virtio_crypto_sym_request *vc_sym_req = 628c2ecf20Sopenharmony_ci container_of(vc_req, struct virtio_crypto_sym_request, base); 638c2ecf20Sopenharmony_ci struct skcipher_request *ablk_req; 648c2ecf20Sopenharmony_ci int error; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* Finish the encrypt or decrypt process */ 678c2ecf20Sopenharmony_ci if (vc_sym_req->type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { 688c2ecf20Sopenharmony_ci switch (vc_req->status) { 698c2ecf20Sopenharmony_ci case VIRTIO_CRYPTO_OK: 708c2ecf20Sopenharmony_ci error = 0; 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci case VIRTIO_CRYPTO_INVSESS: 738c2ecf20Sopenharmony_ci case VIRTIO_CRYPTO_ERR: 748c2ecf20Sopenharmony_ci error = -EINVAL; 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci case VIRTIO_CRYPTO_BADMSG: 778c2ecf20Sopenharmony_ci error = -EBADMSG; 788c2ecf20Sopenharmony_ci break; 798c2ecf20Sopenharmony_ci default: 808c2ecf20Sopenharmony_ci error = -EIO; 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci ablk_req = vc_sym_req->skcipher_req; 848c2ecf20Sopenharmony_ci virtio_crypto_skcipher_finalize_req(vc_sym_req, 858c2ecf20Sopenharmony_ci ablk_req, error); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic u64 virtio_crypto_alg_sg_nents_length(struct scatterlist *sg) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci u64 total = 0; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci for (total = 0; sg; sg = sg_next(sg)) 948c2ecf20Sopenharmony_ci total += sg->length; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return total; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int 1008c2ecf20Sopenharmony_civirtio_crypto_alg_validate_key(int key_len, uint32_t *alg) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci switch (key_len) { 1038c2ecf20Sopenharmony_ci case AES_KEYSIZE_128: 1048c2ecf20Sopenharmony_ci case AES_KEYSIZE_192: 1058c2ecf20Sopenharmony_ci case AES_KEYSIZE_256: 1068c2ecf20Sopenharmony_ci *alg = VIRTIO_CRYPTO_CIPHER_AES_CBC; 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci default: 1098c2ecf20Sopenharmony_ci return -EINVAL; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic int virtio_crypto_alg_skcipher_init_session( 1158c2ecf20Sopenharmony_ci struct virtio_crypto_skcipher_ctx *ctx, 1168c2ecf20Sopenharmony_ci uint32_t alg, const uint8_t *key, 1178c2ecf20Sopenharmony_ci unsigned int keylen, 1188c2ecf20Sopenharmony_ci int encrypt) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct scatterlist outhdr, key_sg, inhdr, *sgs[3]; 1218c2ecf20Sopenharmony_ci struct virtio_crypto *vcrypto = ctx->vcrypto; 1228c2ecf20Sopenharmony_ci int op = encrypt ? VIRTIO_CRYPTO_OP_ENCRYPT : VIRTIO_CRYPTO_OP_DECRYPT; 1238c2ecf20Sopenharmony_ci int err; 1248c2ecf20Sopenharmony_ci unsigned int num_out = 0, num_in = 0; 1258c2ecf20Sopenharmony_ci struct virtio_crypto_op_ctrl_req *ctrl; 1268c2ecf20Sopenharmony_ci struct virtio_crypto_session_input *input; 1278c2ecf20Sopenharmony_ci struct virtio_crypto_sym_create_session_req *sym_create_session; 1288c2ecf20Sopenharmony_ci struct virtio_crypto_ctrl_request *vc_ctrl_req; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* 1318c2ecf20Sopenharmony_ci * Avoid to do DMA from the stack, switch to using 1328c2ecf20Sopenharmony_ci * dynamically-allocated for the key 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci uint8_t *cipher_key = kmemdup(key, keylen, GFP_ATOMIC); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (!cipher_key) 1378c2ecf20Sopenharmony_ci return -ENOMEM; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci vc_ctrl_req = kzalloc(sizeof(*vc_ctrl_req), GFP_KERNEL); 1408c2ecf20Sopenharmony_ci if (!vc_ctrl_req) { 1418c2ecf20Sopenharmony_ci err = -ENOMEM; 1428c2ecf20Sopenharmony_ci goto out; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* Pad ctrl header */ 1468c2ecf20Sopenharmony_ci ctrl = &vc_ctrl_req->ctrl; 1478c2ecf20Sopenharmony_ci ctrl->header.opcode = cpu_to_le32(VIRTIO_CRYPTO_CIPHER_CREATE_SESSION); 1488c2ecf20Sopenharmony_ci ctrl->header.algo = cpu_to_le32(alg); 1498c2ecf20Sopenharmony_ci /* Set the default dataqueue id to 0 */ 1508c2ecf20Sopenharmony_ci ctrl->header.queue_id = 0; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci input = &vc_ctrl_req->input; 1538c2ecf20Sopenharmony_ci input->status = cpu_to_le32(VIRTIO_CRYPTO_ERR); 1548c2ecf20Sopenharmony_ci /* Pad cipher's parameters */ 1558c2ecf20Sopenharmony_ci sym_create_session = &ctrl->u.sym_create_session; 1568c2ecf20Sopenharmony_ci sym_create_session->op_type = cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER); 1578c2ecf20Sopenharmony_ci sym_create_session->u.cipher.para.algo = ctrl->header.algo; 1588c2ecf20Sopenharmony_ci sym_create_session->u.cipher.para.keylen = cpu_to_le32(keylen); 1598c2ecf20Sopenharmony_ci sym_create_session->u.cipher.para.op = cpu_to_le32(op); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci sg_init_one(&outhdr, ctrl, sizeof(*ctrl)); 1628c2ecf20Sopenharmony_ci sgs[num_out++] = &outhdr; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* Set key */ 1658c2ecf20Sopenharmony_ci sg_init_one(&key_sg, cipher_key, keylen); 1668c2ecf20Sopenharmony_ci sgs[num_out++] = &key_sg; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Return status and session id back */ 1698c2ecf20Sopenharmony_ci sg_init_one(&inhdr, input, sizeof(*input)); 1708c2ecf20Sopenharmony_ci sgs[num_out + num_in++] = &inhdr; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci err = virtio_crypto_ctrl_vq_request(vcrypto, sgs, num_out, num_in, vc_ctrl_req); 1738c2ecf20Sopenharmony_ci if (err < 0) 1748c2ecf20Sopenharmony_ci goto out; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (le32_to_cpu(input->status) != VIRTIO_CRYPTO_OK) { 1778c2ecf20Sopenharmony_ci pr_err("virtio_crypto: Create session failed status: %u\n", 1788c2ecf20Sopenharmony_ci le32_to_cpu(input->status)); 1798c2ecf20Sopenharmony_ci err = -EINVAL; 1808c2ecf20Sopenharmony_ci goto out; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (encrypt) 1848c2ecf20Sopenharmony_ci ctx->enc_sess_info.session_id = le64_to_cpu(input->session_id); 1858c2ecf20Sopenharmony_ci else 1868c2ecf20Sopenharmony_ci ctx->dec_sess_info.session_id = le64_to_cpu(input->session_id); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci err = 0; 1898c2ecf20Sopenharmony_ciout: 1908c2ecf20Sopenharmony_ci kfree(vc_ctrl_req); 1918c2ecf20Sopenharmony_ci kfree_sensitive(cipher_key); 1928c2ecf20Sopenharmony_ci return err; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int virtio_crypto_alg_skcipher_close_session( 1968c2ecf20Sopenharmony_ci struct virtio_crypto_skcipher_ctx *ctx, 1978c2ecf20Sopenharmony_ci int encrypt) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct scatterlist outhdr, status_sg, *sgs[2]; 2008c2ecf20Sopenharmony_ci struct virtio_crypto_destroy_session_req *destroy_session; 2018c2ecf20Sopenharmony_ci struct virtio_crypto *vcrypto = ctx->vcrypto; 2028c2ecf20Sopenharmony_ci int err; 2038c2ecf20Sopenharmony_ci unsigned int num_out = 0, num_in = 0; 2048c2ecf20Sopenharmony_ci struct virtio_crypto_op_ctrl_req *ctrl; 2058c2ecf20Sopenharmony_ci struct virtio_crypto_inhdr *ctrl_status; 2068c2ecf20Sopenharmony_ci struct virtio_crypto_ctrl_request *vc_ctrl_req; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci vc_ctrl_req = kzalloc(sizeof(*vc_ctrl_req), GFP_KERNEL); 2098c2ecf20Sopenharmony_ci if (!vc_ctrl_req) 2108c2ecf20Sopenharmony_ci return -ENOMEM; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ctrl_status = &vc_ctrl_req->ctrl_status; 2138c2ecf20Sopenharmony_ci ctrl_status->status = VIRTIO_CRYPTO_ERR; 2148c2ecf20Sopenharmony_ci /* Pad ctrl header */ 2158c2ecf20Sopenharmony_ci ctrl = &vc_ctrl_req->ctrl; 2168c2ecf20Sopenharmony_ci ctrl->header.opcode = cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION); 2178c2ecf20Sopenharmony_ci /* Set the default virtqueue id to 0 */ 2188c2ecf20Sopenharmony_ci ctrl->header.queue_id = 0; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci destroy_session = &ctrl->u.destroy_session; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (encrypt) 2238c2ecf20Sopenharmony_ci destroy_session->session_id = cpu_to_le64(ctx->enc_sess_info.session_id); 2248c2ecf20Sopenharmony_ci else 2258c2ecf20Sopenharmony_ci destroy_session->session_id = cpu_to_le64(ctx->dec_sess_info.session_id); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci sg_init_one(&outhdr, ctrl, sizeof(*ctrl)); 2288c2ecf20Sopenharmony_ci sgs[num_out++] = &outhdr; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Return status and session id back */ 2318c2ecf20Sopenharmony_ci sg_init_one(&status_sg, &ctrl_status->status, sizeof(ctrl_status->status)); 2328c2ecf20Sopenharmony_ci sgs[num_out + num_in++] = &status_sg; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci err = virtio_crypto_ctrl_vq_request(vcrypto, sgs, num_out, num_in, vc_ctrl_req); 2358c2ecf20Sopenharmony_ci if (err < 0) 2368c2ecf20Sopenharmony_ci goto out; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (ctrl_status->status != VIRTIO_CRYPTO_OK) { 2398c2ecf20Sopenharmony_ci pr_err("virtio_crypto: Close session failed status: %u, session_id: 0x%llx\n", 2408c2ecf20Sopenharmony_ci ctrl_status->status, destroy_session->session_id); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci err = -EINVAL; 2438c2ecf20Sopenharmony_ci goto out; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci err = 0; 2478c2ecf20Sopenharmony_ciout: 2488c2ecf20Sopenharmony_ci kfree(vc_ctrl_req); 2498c2ecf20Sopenharmony_ci return err; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int virtio_crypto_alg_skcipher_init_sessions( 2538c2ecf20Sopenharmony_ci struct virtio_crypto_skcipher_ctx *ctx, 2548c2ecf20Sopenharmony_ci const uint8_t *key, unsigned int keylen) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci uint32_t alg; 2578c2ecf20Sopenharmony_ci int ret; 2588c2ecf20Sopenharmony_ci struct virtio_crypto *vcrypto = ctx->vcrypto; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (keylen > vcrypto->max_cipher_key_len) { 2618c2ecf20Sopenharmony_ci pr_err("virtio_crypto: the key is too long\n"); 2628c2ecf20Sopenharmony_ci return -EINVAL; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (virtio_crypto_alg_validate_key(keylen, &alg)) 2668c2ecf20Sopenharmony_ci return -EINVAL; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* Create encryption session */ 2698c2ecf20Sopenharmony_ci ret = virtio_crypto_alg_skcipher_init_session(ctx, 2708c2ecf20Sopenharmony_ci alg, key, keylen, 1); 2718c2ecf20Sopenharmony_ci if (ret) 2728c2ecf20Sopenharmony_ci return ret; 2738c2ecf20Sopenharmony_ci /* Create decryption session */ 2748c2ecf20Sopenharmony_ci ret = virtio_crypto_alg_skcipher_init_session(ctx, 2758c2ecf20Sopenharmony_ci alg, key, keylen, 0); 2768c2ecf20Sopenharmony_ci if (ret) { 2778c2ecf20Sopenharmony_ci virtio_crypto_alg_skcipher_close_session(ctx, 1); 2788c2ecf20Sopenharmony_ci return ret; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci return 0; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/* Note: kernel crypto API realization */ 2848c2ecf20Sopenharmony_cistatic int virtio_crypto_skcipher_setkey(struct crypto_skcipher *tfm, 2858c2ecf20Sopenharmony_ci const uint8_t *key, 2868c2ecf20Sopenharmony_ci unsigned int keylen) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 2898c2ecf20Sopenharmony_ci uint32_t alg; 2908c2ecf20Sopenharmony_ci int ret; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci ret = virtio_crypto_alg_validate_key(keylen, &alg); 2938c2ecf20Sopenharmony_ci if (ret) 2948c2ecf20Sopenharmony_ci return ret; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!ctx->vcrypto) { 2978c2ecf20Sopenharmony_ci /* New key */ 2988c2ecf20Sopenharmony_ci int node = virtio_crypto_get_current_node(); 2998c2ecf20Sopenharmony_ci struct virtio_crypto *vcrypto = 3008c2ecf20Sopenharmony_ci virtcrypto_get_dev_node(node, 3018c2ecf20Sopenharmony_ci VIRTIO_CRYPTO_SERVICE_CIPHER, alg); 3028c2ecf20Sopenharmony_ci if (!vcrypto) { 3038c2ecf20Sopenharmony_ci pr_err("virtio_crypto: Could not find a virtio device in the system or unsupported algo\n"); 3048c2ecf20Sopenharmony_ci return -ENODEV; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci ctx->vcrypto = vcrypto; 3088c2ecf20Sopenharmony_ci } else { 3098c2ecf20Sopenharmony_ci /* Rekeying, we should close the created sessions previously */ 3108c2ecf20Sopenharmony_ci virtio_crypto_alg_skcipher_close_session(ctx, 1); 3118c2ecf20Sopenharmony_ci virtio_crypto_alg_skcipher_close_session(ctx, 0); 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci ret = virtio_crypto_alg_skcipher_init_sessions(ctx, key, keylen); 3158c2ecf20Sopenharmony_ci if (ret) { 3168c2ecf20Sopenharmony_ci virtcrypto_dev_put(ctx->vcrypto); 3178c2ecf20Sopenharmony_ci ctx->vcrypto = NULL; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return ret; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int 3268c2ecf20Sopenharmony_ci__virtio_crypto_skcipher_do_req(struct virtio_crypto_sym_request *vc_sym_req, 3278c2ecf20Sopenharmony_ci struct skcipher_request *req, 3288c2ecf20Sopenharmony_ci struct data_queue *data_vq) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 3318c2ecf20Sopenharmony_ci struct virtio_crypto_skcipher_ctx *ctx = vc_sym_req->skcipher_ctx; 3328c2ecf20Sopenharmony_ci struct virtio_crypto_request *vc_req = &vc_sym_req->base; 3338c2ecf20Sopenharmony_ci unsigned int ivsize = crypto_skcipher_ivsize(tfm); 3348c2ecf20Sopenharmony_ci struct virtio_crypto *vcrypto = ctx->vcrypto; 3358c2ecf20Sopenharmony_ci struct virtio_crypto_op_data_req *req_data; 3368c2ecf20Sopenharmony_ci int src_nents, dst_nents; 3378c2ecf20Sopenharmony_ci int err; 3388c2ecf20Sopenharmony_ci unsigned long flags; 3398c2ecf20Sopenharmony_ci struct scatterlist outhdr, iv_sg, status_sg, **sgs; 3408c2ecf20Sopenharmony_ci u64 dst_len; 3418c2ecf20Sopenharmony_ci unsigned int num_out = 0, num_in = 0; 3428c2ecf20Sopenharmony_ci int sg_total; 3438c2ecf20Sopenharmony_ci uint8_t *iv; 3448c2ecf20Sopenharmony_ci struct scatterlist *sg; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci src_nents = sg_nents_for_len(req->src, req->cryptlen); 3478c2ecf20Sopenharmony_ci if (src_nents < 0) { 3488c2ecf20Sopenharmony_ci pr_err("Invalid number of src SG.\n"); 3498c2ecf20Sopenharmony_ci return src_nents; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci dst_nents = sg_nents(req->dst); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci pr_debug("virtio_crypto: Number of sgs (src_nents: %d, dst_nents: %d)\n", 3558c2ecf20Sopenharmony_ci src_nents, dst_nents); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Why 3? outhdr + iv + inhdr */ 3588c2ecf20Sopenharmony_ci sg_total = src_nents + dst_nents + 3; 3598c2ecf20Sopenharmony_ci sgs = kcalloc_node(sg_total, sizeof(*sgs), GFP_KERNEL, 3608c2ecf20Sopenharmony_ci dev_to_node(&vcrypto->vdev->dev)); 3618c2ecf20Sopenharmony_ci if (!sgs) 3628c2ecf20Sopenharmony_ci return -ENOMEM; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci req_data = kzalloc_node(sizeof(*req_data), GFP_KERNEL, 3658c2ecf20Sopenharmony_ci dev_to_node(&vcrypto->vdev->dev)); 3668c2ecf20Sopenharmony_ci if (!req_data) { 3678c2ecf20Sopenharmony_ci kfree(sgs); 3688c2ecf20Sopenharmony_ci return -ENOMEM; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci vc_req->req_data = req_data; 3728c2ecf20Sopenharmony_ci vc_sym_req->type = VIRTIO_CRYPTO_SYM_OP_CIPHER; 3738c2ecf20Sopenharmony_ci /* Head of operation */ 3748c2ecf20Sopenharmony_ci if (vc_sym_req->encrypt) { 3758c2ecf20Sopenharmony_ci req_data->header.session_id = 3768c2ecf20Sopenharmony_ci cpu_to_le64(ctx->enc_sess_info.session_id); 3778c2ecf20Sopenharmony_ci req_data->header.opcode = 3788c2ecf20Sopenharmony_ci cpu_to_le32(VIRTIO_CRYPTO_CIPHER_ENCRYPT); 3798c2ecf20Sopenharmony_ci } else { 3808c2ecf20Sopenharmony_ci req_data->header.session_id = 3818c2ecf20Sopenharmony_ci cpu_to_le64(ctx->dec_sess_info.session_id); 3828c2ecf20Sopenharmony_ci req_data->header.opcode = 3838c2ecf20Sopenharmony_ci cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DECRYPT); 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci req_data->u.sym_req.op_type = cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER); 3868c2ecf20Sopenharmony_ci req_data->u.sym_req.u.cipher.para.iv_len = cpu_to_le32(ivsize); 3878c2ecf20Sopenharmony_ci req_data->u.sym_req.u.cipher.para.src_data_len = 3888c2ecf20Sopenharmony_ci cpu_to_le32(req->cryptlen); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci dst_len = virtio_crypto_alg_sg_nents_length(req->dst); 3918c2ecf20Sopenharmony_ci if (unlikely(dst_len > U32_MAX)) { 3928c2ecf20Sopenharmony_ci pr_err("virtio_crypto: The dst_len is beyond U32_MAX\n"); 3938c2ecf20Sopenharmony_ci err = -EINVAL; 3948c2ecf20Sopenharmony_ci goto free; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci dst_len = min_t(unsigned int, req->cryptlen, dst_len); 3988c2ecf20Sopenharmony_ci pr_debug("virtio_crypto: src_len: %u, dst_len: %llu\n", 3998c2ecf20Sopenharmony_ci req->cryptlen, dst_len); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (unlikely(req->cryptlen + dst_len + ivsize + 4028c2ecf20Sopenharmony_ci sizeof(vc_req->status) > vcrypto->max_size)) { 4038c2ecf20Sopenharmony_ci pr_err("virtio_crypto: The length is too big\n"); 4048c2ecf20Sopenharmony_ci err = -EINVAL; 4058c2ecf20Sopenharmony_ci goto free; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci req_data->u.sym_req.u.cipher.para.dst_data_len = 4098c2ecf20Sopenharmony_ci cpu_to_le32((uint32_t)dst_len); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Outhdr */ 4128c2ecf20Sopenharmony_ci sg_init_one(&outhdr, req_data, sizeof(*req_data)); 4138c2ecf20Sopenharmony_ci sgs[num_out++] = &outhdr; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* IV */ 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* 4188c2ecf20Sopenharmony_ci * Avoid to do DMA from the stack, switch to using 4198c2ecf20Sopenharmony_ci * dynamically-allocated for the IV 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci iv = kzalloc_node(ivsize, GFP_ATOMIC, 4228c2ecf20Sopenharmony_ci dev_to_node(&vcrypto->vdev->dev)); 4238c2ecf20Sopenharmony_ci if (!iv) { 4248c2ecf20Sopenharmony_ci err = -ENOMEM; 4258c2ecf20Sopenharmony_ci goto free; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci memcpy(iv, req->iv, ivsize); 4288c2ecf20Sopenharmony_ci if (!vc_sym_req->encrypt) 4298c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(req->iv, req->src, 4308c2ecf20Sopenharmony_ci req->cryptlen - AES_BLOCK_SIZE, 4318c2ecf20Sopenharmony_ci AES_BLOCK_SIZE, 0); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci sg_init_one(&iv_sg, iv, ivsize); 4348c2ecf20Sopenharmony_ci sgs[num_out++] = &iv_sg; 4358c2ecf20Sopenharmony_ci vc_sym_req->iv = iv; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* Source data */ 4388c2ecf20Sopenharmony_ci for (sg = req->src; src_nents; sg = sg_next(sg), src_nents--) 4398c2ecf20Sopenharmony_ci sgs[num_out++] = sg; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Destination data */ 4428c2ecf20Sopenharmony_ci for (sg = req->dst; sg; sg = sg_next(sg)) 4438c2ecf20Sopenharmony_ci sgs[num_out + num_in++] = sg; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* Status */ 4468c2ecf20Sopenharmony_ci sg_init_one(&status_sg, &vc_req->status, sizeof(vc_req->status)); 4478c2ecf20Sopenharmony_ci sgs[num_out + num_in++] = &status_sg; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci vc_req->sgs = sgs; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci spin_lock_irqsave(&data_vq->lock, flags); 4528c2ecf20Sopenharmony_ci err = virtqueue_add_sgs(data_vq->vq, sgs, num_out, 4538c2ecf20Sopenharmony_ci num_in, vc_req, GFP_ATOMIC); 4548c2ecf20Sopenharmony_ci virtqueue_kick(data_vq->vq); 4558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&data_vq->lock, flags); 4568c2ecf20Sopenharmony_ci if (unlikely(err < 0)) 4578c2ecf20Sopenharmony_ci goto free_iv; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return 0; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cifree_iv: 4628c2ecf20Sopenharmony_ci kfree_sensitive(iv); 4638c2ecf20Sopenharmony_cifree: 4648c2ecf20Sopenharmony_ci kfree_sensitive(req_data); 4658c2ecf20Sopenharmony_ci kfree(sgs); 4668c2ecf20Sopenharmony_ci return err; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic int virtio_crypto_skcipher_encrypt(struct skcipher_request *req) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct crypto_skcipher *atfm = crypto_skcipher_reqtfm(req); 4728c2ecf20Sopenharmony_ci struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(atfm); 4738c2ecf20Sopenharmony_ci struct virtio_crypto_sym_request *vc_sym_req = 4748c2ecf20Sopenharmony_ci skcipher_request_ctx(req); 4758c2ecf20Sopenharmony_ci struct virtio_crypto_request *vc_req = &vc_sym_req->base; 4768c2ecf20Sopenharmony_ci struct virtio_crypto *vcrypto = ctx->vcrypto; 4778c2ecf20Sopenharmony_ci /* Use the first data virtqueue as default */ 4788c2ecf20Sopenharmony_ci struct data_queue *data_vq = &vcrypto->data_vq[0]; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (!req->cryptlen) 4818c2ecf20Sopenharmony_ci return 0; 4828c2ecf20Sopenharmony_ci if (req->cryptlen % AES_BLOCK_SIZE) 4838c2ecf20Sopenharmony_ci return -EINVAL; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci vc_req->dataq = data_vq; 4868c2ecf20Sopenharmony_ci vc_req->alg_cb = virtio_crypto_dataq_sym_callback; 4878c2ecf20Sopenharmony_ci vc_sym_req->skcipher_ctx = ctx; 4888c2ecf20Sopenharmony_ci vc_sym_req->skcipher_req = req; 4898c2ecf20Sopenharmony_ci vc_sym_req->encrypt = true; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return crypto_transfer_skcipher_request_to_engine(data_vq->engine, req); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int virtio_crypto_skcipher_decrypt(struct skcipher_request *req) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct crypto_skcipher *atfm = crypto_skcipher_reqtfm(req); 4978c2ecf20Sopenharmony_ci struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(atfm); 4988c2ecf20Sopenharmony_ci struct virtio_crypto_sym_request *vc_sym_req = 4998c2ecf20Sopenharmony_ci skcipher_request_ctx(req); 5008c2ecf20Sopenharmony_ci struct virtio_crypto_request *vc_req = &vc_sym_req->base; 5018c2ecf20Sopenharmony_ci struct virtio_crypto *vcrypto = ctx->vcrypto; 5028c2ecf20Sopenharmony_ci /* Use the first data virtqueue as default */ 5038c2ecf20Sopenharmony_ci struct data_queue *data_vq = &vcrypto->data_vq[0]; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (!req->cryptlen) 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci if (req->cryptlen % AES_BLOCK_SIZE) 5088c2ecf20Sopenharmony_ci return -EINVAL; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci vc_req->dataq = data_vq; 5118c2ecf20Sopenharmony_ci vc_req->alg_cb = virtio_crypto_dataq_sym_callback; 5128c2ecf20Sopenharmony_ci vc_sym_req->skcipher_ctx = ctx; 5138c2ecf20Sopenharmony_ci vc_sym_req->skcipher_req = req; 5148c2ecf20Sopenharmony_ci vc_sym_req->encrypt = false; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return crypto_transfer_skcipher_request_to_engine(data_vq->engine, req); 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic int virtio_crypto_skcipher_init(struct crypto_skcipher *tfm) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct virtio_crypto_sym_request)); 5248c2ecf20Sopenharmony_ci ctx->tfm = tfm; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci ctx->enginectx.op.do_one_request = virtio_crypto_skcipher_crypt_req; 5278c2ecf20Sopenharmony_ci ctx->enginectx.op.prepare_request = NULL; 5288c2ecf20Sopenharmony_ci ctx->enginectx.op.unprepare_request = NULL; 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic void virtio_crypto_skcipher_exit(struct crypto_skcipher *tfm) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci if (!ctx->vcrypto) 5378c2ecf20Sopenharmony_ci return; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci virtio_crypto_alg_skcipher_close_session(ctx, 1); 5408c2ecf20Sopenharmony_ci virtio_crypto_alg_skcipher_close_session(ctx, 0); 5418c2ecf20Sopenharmony_ci virtcrypto_dev_put(ctx->vcrypto); 5428c2ecf20Sopenharmony_ci ctx->vcrypto = NULL; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ciint virtio_crypto_skcipher_crypt_req( 5468c2ecf20Sopenharmony_ci struct crypto_engine *engine, void *vreq) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct skcipher_request *req = container_of(vreq, struct skcipher_request, base); 5498c2ecf20Sopenharmony_ci struct virtio_crypto_sym_request *vc_sym_req = 5508c2ecf20Sopenharmony_ci skcipher_request_ctx(req); 5518c2ecf20Sopenharmony_ci struct virtio_crypto_request *vc_req = &vc_sym_req->base; 5528c2ecf20Sopenharmony_ci struct data_queue *data_vq = vc_req->dataq; 5538c2ecf20Sopenharmony_ci int ret; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci ret = __virtio_crypto_skcipher_do_req(vc_sym_req, req, data_vq); 5568c2ecf20Sopenharmony_ci if (ret < 0) 5578c2ecf20Sopenharmony_ci return ret; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci virtqueue_kick(data_vq->vq); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci return 0; 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic void virtio_crypto_skcipher_finalize_req( 5658c2ecf20Sopenharmony_ci struct virtio_crypto_sym_request *vc_sym_req, 5668c2ecf20Sopenharmony_ci struct skcipher_request *req, 5678c2ecf20Sopenharmony_ci int err) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci if (vc_sym_req->encrypt) 5708c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(req->iv, req->dst, 5718c2ecf20Sopenharmony_ci req->cryptlen - AES_BLOCK_SIZE, 5728c2ecf20Sopenharmony_ci AES_BLOCK_SIZE, 0); 5738c2ecf20Sopenharmony_ci kfree_sensitive(vc_sym_req->iv); 5748c2ecf20Sopenharmony_ci virtcrypto_clear_request(&vc_sym_req->base); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci crypto_finalize_skcipher_request(vc_sym_req->base.dataq->engine, 5778c2ecf20Sopenharmony_ci req, err); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic struct virtio_crypto_algo virtio_crypto_algs[] = { { 5818c2ecf20Sopenharmony_ci .algonum = VIRTIO_CRYPTO_CIPHER_AES_CBC, 5828c2ecf20Sopenharmony_ci .service = VIRTIO_CRYPTO_SERVICE_CIPHER, 5838c2ecf20Sopenharmony_ci .algo = { 5848c2ecf20Sopenharmony_ci .base.cra_name = "cbc(aes)", 5858c2ecf20Sopenharmony_ci .base.cra_driver_name = "virtio_crypto_aes_cbc", 5868c2ecf20Sopenharmony_ci .base.cra_priority = 150, 5878c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_ASYNC | 5888c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 5898c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 5908c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct virtio_crypto_skcipher_ctx), 5918c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 5928c2ecf20Sopenharmony_ci .init = virtio_crypto_skcipher_init, 5938c2ecf20Sopenharmony_ci .exit = virtio_crypto_skcipher_exit, 5948c2ecf20Sopenharmony_ci .setkey = virtio_crypto_skcipher_setkey, 5958c2ecf20Sopenharmony_ci .decrypt = virtio_crypto_skcipher_decrypt, 5968c2ecf20Sopenharmony_ci .encrypt = virtio_crypto_skcipher_encrypt, 5978c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 5988c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 5998c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 6008c2ecf20Sopenharmony_ci }, 6018c2ecf20Sopenharmony_ci} }; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ciint virtio_crypto_algs_register(struct virtio_crypto *vcrypto) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci int ret = 0; 6068c2ecf20Sopenharmony_ci int i = 0; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci mutex_lock(&algs_lock); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(virtio_crypto_algs); i++) { 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci uint32_t service = virtio_crypto_algs[i].service; 6138c2ecf20Sopenharmony_ci uint32_t algonum = virtio_crypto_algs[i].algonum; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (!virtcrypto_algo_is_supported(vcrypto, service, algonum)) 6168c2ecf20Sopenharmony_ci continue; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (virtio_crypto_algs[i].active_devs == 0) { 6198c2ecf20Sopenharmony_ci ret = crypto_register_skcipher(&virtio_crypto_algs[i].algo); 6208c2ecf20Sopenharmony_ci if (ret) 6218c2ecf20Sopenharmony_ci goto unlock; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci virtio_crypto_algs[i].active_devs++; 6258c2ecf20Sopenharmony_ci dev_info(&vcrypto->vdev->dev, "Registered algo %s\n", 6268c2ecf20Sopenharmony_ci virtio_crypto_algs[i].algo.base.cra_name); 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ciunlock: 6308c2ecf20Sopenharmony_ci mutex_unlock(&algs_lock); 6318c2ecf20Sopenharmony_ci return ret; 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_civoid virtio_crypto_algs_unregister(struct virtio_crypto *vcrypto) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci int i = 0; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci mutex_lock(&algs_lock); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(virtio_crypto_algs); i++) { 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci uint32_t service = virtio_crypto_algs[i].service; 6438c2ecf20Sopenharmony_ci uint32_t algonum = virtio_crypto_algs[i].algonum; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (virtio_crypto_algs[i].active_devs == 0 || 6468c2ecf20Sopenharmony_ci !virtcrypto_algo_is_supported(vcrypto, service, algonum)) 6478c2ecf20Sopenharmony_ci continue; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (virtio_crypto_algs[i].active_devs == 1) 6508c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&virtio_crypto_algs[i].algo); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci virtio_crypto_algs[i].active_devs--; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci mutex_unlock(&algs_lock); 6568c2ecf20Sopenharmony_ci} 657