1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2019 Samsung Electronics Co., Ltd. 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/string.h> 8 #include <linux/err.h> 9 #include <linux/slab.h> 10 #include <linux/wait.h> 11 #include <linux/sched.h> 12 13 #include "glob.h" 14 #include "crypto_ctx.h" 15 16 struct crypto_ctx_list { 17 spinlock_t ctx_lock; 18 int avail_ctx; 19 struct list_head idle_ctx; 20 wait_queue_head_t ctx_wait; 21 }; 22 23 static struct crypto_ctx_list ctx_list; 24 25 static inline void free_aead(struct crypto_aead *aead) 26 { 27 if (aead) 28 crypto_free_aead(aead); 29 } 30 31 static struct crypto_aead *alloc_aead(int id) 32 { 33 struct crypto_aead *tfm = NULL; 34 35 switch (id) { 36 case CRYPTO_AEAD_AES_GCM: 37 tfm = crypto_alloc_aead("gcm(aes)", 0, 0); 38 break; 39 case CRYPTO_AEAD_AES_CCM: 40 tfm = crypto_alloc_aead("ccm(aes)", 0, 0); 41 break; 42 default: 43 pr_err("Does not support encrypt ahead(id : %d)\n", id); 44 return NULL; 45 } 46 47 if (IS_ERR(tfm)) { 48 pr_err("Failed to alloc encrypt aead : %ld\n", PTR_ERR(tfm)); 49 return NULL; 50 } 51 52 return tfm; 53 } 54 55 static void ctx_free(struct ksmbd_crypto_ctx *ctx) 56 { 57 int i; 58 59 for (i = 0; i < CRYPTO_AEAD_MAX; i++) 60 free_aead(ctx->ccmaes[i]); 61 kfree(ctx); 62 } 63 64 static struct ksmbd_crypto_ctx *ksmbd_find_crypto_ctx(void) 65 { 66 struct ksmbd_crypto_ctx *ctx; 67 68 while (1) { 69 spin_lock(&ctx_list.ctx_lock); 70 if (!list_empty(&ctx_list.idle_ctx)) { 71 ctx = list_entry(ctx_list.idle_ctx.next, 72 struct ksmbd_crypto_ctx, 73 list); 74 list_del(&ctx->list); 75 spin_unlock(&ctx_list.ctx_lock); 76 return ctx; 77 } 78 79 if (ctx_list.avail_ctx > num_online_cpus()) { 80 spin_unlock(&ctx_list.ctx_lock); 81 wait_event(ctx_list.ctx_wait, 82 !list_empty(&ctx_list.idle_ctx)); 83 continue; 84 } 85 86 ctx_list.avail_ctx++; 87 spin_unlock(&ctx_list.ctx_lock); 88 89 ctx = kzalloc_obj(struct ksmbd_crypto_ctx, KSMBD_DEFAULT_GFP); 90 if (!ctx) { 91 spin_lock(&ctx_list.ctx_lock); 92 ctx_list.avail_ctx--; 93 spin_unlock(&ctx_list.ctx_lock); 94 wait_event(ctx_list.ctx_wait, 95 !list_empty(&ctx_list.idle_ctx)); 96 continue; 97 } 98 break; 99 } 100 return ctx; 101 } 102 103 void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx) 104 { 105 if (!ctx) 106 return; 107 108 spin_lock(&ctx_list.ctx_lock); 109 if (ctx_list.avail_ctx <= num_online_cpus()) { 110 list_add(&ctx->list, &ctx_list.idle_ctx); 111 spin_unlock(&ctx_list.ctx_lock); 112 wake_up(&ctx_list.ctx_wait); 113 return; 114 } 115 116 ctx_list.avail_ctx--; 117 spin_unlock(&ctx_list.ctx_lock); 118 ctx_free(ctx); 119 } 120 121 static struct ksmbd_crypto_ctx *____crypto_aead_ctx_find(int id) 122 { 123 struct ksmbd_crypto_ctx *ctx; 124 125 if (id >= CRYPTO_AEAD_MAX) 126 return NULL; 127 128 ctx = ksmbd_find_crypto_ctx(); 129 if (ctx->ccmaes[id]) 130 return ctx; 131 132 ctx->ccmaes[id] = alloc_aead(id); 133 if (ctx->ccmaes[id]) 134 return ctx; 135 ksmbd_release_crypto_ctx(ctx); 136 return NULL; 137 } 138 139 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void) 140 { 141 return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_GCM); 142 } 143 144 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void) 145 { 146 return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_CCM); 147 } 148 149 void ksmbd_crypto_destroy(void) 150 { 151 struct ksmbd_crypto_ctx *ctx; 152 153 while (!list_empty(&ctx_list.idle_ctx)) { 154 ctx = list_entry(ctx_list.idle_ctx.next, 155 struct ksmbd_crypto_ctx, 156 list); 157 list_del(&ctx->list); 158 ctx_free(ctx); 159 } 160 } 161 162 int ksmbd_crypto_create(void) 163 { 164 struct ksmbd_crypto_ctx *ctx; 165 166 spin_lock_init(&ctx_list.ctx_lock); 167 INIT_LIST_HEAD(&ctx_list.idle_ctx); 168 init_waitqueue_head(&ctx_list.ctx_wait); 169 ctx_list.avail_ctx = 1; 170 171 ctx = kzalloc_obj(struct ksmbd_crypto_ctx, KSMBD_DEFAULT_GFP); 172 if (!ctx) 173 return -ENOMEM; 174 list_add(&ctx->list, &ctx_list.idle_ctx); 175 return 0; 176 } 177