Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  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
 16struct 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
 23static struct crypto_ctx_list ctx_list;
 24
 25static inline void free_aead(struct crypto_aead *aead)
 26{
 27	if (aead)
 28		crypto_free_aead(aead);
 29}
 30
 31static void free_shash(struct shash_desc *shash)
 32{
 33	if (shash) {
 34		crypto_free_shash(shash->tfm);
 35		kfree(shash);
 36	}
 37}
 38
 39static struct crypto_aead *alloc_aead(int id)
 40{
 41	struct crypto_aead *tfm = NULL;
 42
 43	switch (id) {
 44	case CRYPTO_AEAD_AES_GCM:
 45		tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
 46		break;
 47	case CRYPTO_AEAD_AES_CCM:
 48		tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
 49		break;
 50	default:
 51		pr_err("Does not support encrypt ahead(id : %d)\n", id);
 52		return NULL;
 53	}
 54
 55	if (IS_ERR(tfm)) {
 56		pr_err("Failed to alloc encrypt aead : %ld\n", PTR_ERR(tfm));
 57		return NULL;
 58	}
 59
 60	return tfm;
 61}
 62
 63static struct shash_desc *alloc_shash_desc(int id)
 64{
 65	struct crypto_shash *tfm = NULL;
 66	struct shash_desc *shash;
 67
 68	switch (id) {
 69	case CRYPTO_SHASH_HMACMD5:
 70		tfm = crypto_alloc_shash("hmac(md5)", 0, 0);
 71		break;
 72	case CRYPTO_SHASH_HMACSHA256:
 73		tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
 74		break;
 75	case CRYPTO_SHASH_CMACAES:
 76		tfm = crypto_alloc_shash("cmac(aes)", 0, 0);
 77		break;
 78	case CRYPTO_SHASH_SHA256:
 79		tfm = crypto_alloc_shash("sha256", 0, 0);
 80		break;
 81	case CRYPTO_SHASH_SHA512:
 82		tfm = crypto_alloc_shash("sha512", 0, 0);
 83		break;
 84	default:
 85		return NULL;
 86	}
 87
 88	if (IS_ERR(tfm))
 89		return NULL;
 90
 91	shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm),
 92			GFP_KERNEL);
 93	if (!shash)
 94		crypto_free_shash(tfm);
 95	else
 96		shash->tfm = tfm;
 97	return shash;
 98}
 99
100static void ctx_free(struct ksmbd_crypto_ctx *ctx)
101{
102	int i;
103
104	for (i = 0; i < CRYPTO_SHASH_MAX; i++)
105		free_shash(ctx->desc[i]);
106	for (i = 0; i < CRYPTO_AEAD_MAX; i++)
107		free_aead(ctx->ccmaes[i]);
108	kfree(ctx);
109}
110
111static struct ksmbd_crypto_ctx *ksmbd_find_crypto_ctx(void)
112{
113	struct ksmbd_crypto_ctx *ctx;
114
115	while (1) {
116		spin_lock(&ctx_list.ctx_lock);
117		if (!list_empty(&ctx_list.idle_ctx)) {
118			ctx = list_entry(ctx_list.idle_ctx.next,
119					 struct ksmbd_crypto_ctx,
120					 list);
121			list_del(&ctx->list);
122			spin_unlock(&ctx_list.ctx_lock);
123			return ctx;
124		}
125
126		if (ctx_list.avail_ctx > num_online_cpus()) {
127			spin_unlock(&ctx_list.ctx_lock);
128			wait_event(ctx_list.ctx_wait,
129				   !list_empty(&ctx_list.idle_ctx));
130			continue;
131		}
132
133		ctx_list.avail_ctx++;
134		spin_unlock(&ctx_list.ctx_lock);
135
136		ctx = kzalloc(sizeof(struct ksmbd_crypto_ctx), GFP_KERNEL);
137		if (!ctx) {
138			spin_lock(&ctx_list.ctx_lock);
139			ctx_list.avail_ctx--;
140			spin_unlock(&ctx_list.ctx_lock);
141			wait_event(ctx_list.ctx_wait,
142				   !list_empty(&ctx_list.idle_ctx));
143			continue;
144		}
145		break;
146	}
147	return ctx;
148}
149
150void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx)
151{
152	if (!ctx)
153		return;
154
155	spin_lock(&ctx_list.ctx_lock);
156	if (ctx_list.avail_ctx <= num_online_cpus()) {
157		list_add(&ctx->list, &ctx_list.idle_ctx);
158		spin_unlock(&ctx_list.ctx_lock);
159		wake_up(&ctx_list.ctx_wait);
160		return;
161	}
162
163	ctx_list.avail_ctx--;
164	spin_unlock(&ctx_list.ctx_lock);
165	ctx_free(ctx);
166}
167
168static struct ksmbd_crypto_ctx *____crypto_shash_ctx_find(int id)
169{
170	struct ksmbd_crypto_ctx *ctx;
171
172	if (id >= CRYPTO_SHASH_MAX)
173		return NULL;
174
175	ctx = ksmbd_find_crypto_ctx();
176	if (ctx->desc[id])
177		return ctx;
178
179	ctx->desc[id] = alloc_shash_desc(id);
180	if (ctx->desc[id])
181		return ctx;
182	ksmbd_release_crypto_ctx(ctx);
183	return NULL;
184}
185
186struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void)
187{
188	return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACMD5);
189}
190
191struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacsha256(void)
192{
193	return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACSHA256);
194}
195
196struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void)
197{
198	return ____crypto_shash_ctx_find(CRYPTO_SHASH_CMACAES);
199}
200
201struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha256(void)
202{
203	return ____crypto_shash_ctx_find(CRYPTO_SHASH_SHA256);
204}
205
206struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha512(void)
207{
208	return ____crypto_shash_ctx_find(CRYPTO_SHASH_SHA512);
209}
210
211static struct ksmbd_crypto_ctx *____crypto_aead_ctx_find(int id)
212{
213	struct ksmbd_crypto_ctx *ctx;
214
215	if (id >= CRYPTO_AEAD_MAX)
216		return NULL;
217
218	ctx = ksmbd_find_crypto_ctx();
219	if (ctx->ccmaes[id])
220		return ctx;
221
222	ctx->ccmaes[id] = alloc_aead(id);
223	if (ctx->ccmaes[id])
224		return ctx;
225	ksmbd_release_crypto_ctx(ctx);
226	return NULL;
227}
228
229struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void)
230{
231	return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_GCM);
232}
233
234struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void)
235{
236	return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_CCM);
237}
238
239void ksmbd_crypto_destroy(void)
240{
241	struct ksmbd_crypto_ctx *ctx;
242
243	while (!list_empty(&ctx_list.idle_ctx)) {
244		ctx = list_entry(ctx_list.idle_ctx.next,
245				 struct ksmbd_crypto_ctx,
246				 list);
247		list_del(&ctx->list);
248		ctx_free(ctx);
249	}
250}
251
252int ksmbd_crypto_create(void)
253{
254	struct ksmbd_crypto_ctx *ctx;
255
256	spin_lock_init(&ctx_list.ctx_lock);
257	INIT_LIST_HEAD(&ctx_list.idle_ctx);
258	init_waitqueue_head(&ctx_list.ctx_wait);
259	ctx_list.avail_ctx = 1;
260
261	ctx = kzalloc(sizeof(struct ksmbd_crypto_ctx), GFP_KERNEL);
262	if (!ctx)
263		return -ENOMEM;
264	list_add(&ctx->list, &ctx_list.idle_ctx);
265	return 0;
266}