crypto.c revision 159240
1104476Ssam/*	$OpenBSD: crypto.c,v 1.38 2002/06/11 11:14:29 beck Exp $	*/
2139825Simp/*-
3104476Ssam * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
4104476Ssam *
5104476Ssam * This code was written by Angelos D. Keromytis in Athens, Greece, in
6104476Ssam * February 2000. Network Security Technologies Inc. (NSTI) kindly
7104476Ssam * supported the development of this code.
8104476Ssam *
9104476Ssam * Copyright (c) 2000, 2001 Angelos D. Keromytis
10104476Ssam *
11104476Ssam * Permission to use, copy, and modify this software with or without fee
12104476Ssam * is hereby granted, provided that this entire notice is included in
13104476Ssam * all source code copies of any software which is or includes a copy or
14104476Ssam * modification of this software.
15104476Ssam *
16104476Ssam * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
17104476Ssam * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
18104476Ssam * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
19104476Ssam * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
20104476Ssam * PURPOSE.
21104476Ssam */
22116191Sobrien
23116191Sobrien#include <sys/cdefs.h>
24116191Sobrien__FBSDID("$FreeBSD: head/sys/opencrypto/crypto.c 159240 2006-06-04 22:12:08Z pjd $");
25116191Sobrien
26108587Ssam#define	CRYPTO_TIMING				/* enable timing support */
27104476Ssam
28104476Ssam#include <sys/param.h>
29104476Ssam#include <sys/systm.h>
30104476Ssam#include <sys/eventhandler.h>
31104476Ssam#include <sys/kernel.h>
32104476Ssam#include <sys/kthread.h>
33104476Ssam#include <sys/lock.h>
34129880Sphk#include <sys/module.h>
35104476Ssam#include <sys/mutex.h>
36104476Ssam#include <sys/malloc.h>
37104476Ssam#include <sys/proc.h>
38104476Ssam#include <sys/sysctl.h>
39104476Ssam
40104476Ssam#include <vm/uma.h>
41104476Ssam#include <opencrypto/cryptodev.h>
42104628Ssam#include <opencrypto/xform.h>			/* XXX for M_XDATA */
43104476Ssam
44104476Ssam/*
45104476Ssam * Crypto drivers register themselves by allocating a slot in the
46104476Ssam * crypto_drivers table with crypto_get_driverid() and then registering
47104476Ssam * each algorithm they support with crypto_register() and crypto_kregister().
48104476Ssam */
49104476Ssamstatic	struct mtx crypto_drivers_mtx;		/* lock on driver table */
50104476Ssam#define	CRYPTO_DRIVER_LOCK()	mtx_lock(&crypto_drivers_mtx)
51104476Ssam#define	CRYPTO_DRIVER_UNLOCK()	mtx_unlock(&crypto_drivers_mtx)
52104476Ssamstatic	struct cryptocap *crypto_drivers = NULL;
53104476Ssamstatic	int crypto_drivers_num = 0;
54104476Ssam
55104476Ssam/*
56104476Ssam * There are two queues for crypto requests; one for symmetric (e.g.
57104476Ssam * cipher) operations and one for asymmetric (e.g. MOD)operations.
58104476Ssam * A single mutex is used to lock access to both queues.  We could
59104476Ssam * have one per-queue but having one simplifies handling of block/unblock
60104476Ssam * operations.
61104476Ssam */
62158827Spjdstatic	int crp_sleep = 0;
63104476Ssamstatic	TAILQ_HEAD(,cryptop) crp_q;		/* request queues */
64104476Ssamstatic	TAILQ_HEAD(,cryptkop) crp_kq;
65104476Ssamstatic	struct mtx crypto_q_mtx;
66104476Ssam#define	CRYPTO_Q_LOCK()		mtx_lock(&crypto_q_mtx)
67104476Ssam#define	CRYPTO_Q_UNLOCK()	mtx_unlock(&crypto_q_mtx)
68104476Ssam
69104476Ssam/*
70104476Ssam * There are two queues for processing completed crypto requests; one
71104476Ssam * for the symmetric and one for the asymmetric ops.  We only need one
72104476Ssam * but have two to avoid type futzing (cryptop vs. cryptkop).  A single
73104476Ssam * mutex is used to lock access to both queues.  Note that this lock
74104476Ssam * must be separate from the lock on request queues to insure driver
75104476Ssam * callbacks don't generate lock order reversals.
76104476Ssam */
77104476Ssamstatic	TAILQ_HEAD(,cryptop) crp_ret_q;		/* callback queues */
78104476Ssamstatic	TAILQ_HEAD(,cryptkop) crp_ret_kq;
79104476Ssamstatic	struct mtx crypto_ret_q_mtx;
80104476Ssam#define	CRYPTO_RETQ_LOCK()	mtx_lock(&crypto_ret_q_mtx)
81104476Ssam#define	CRYPTO_RETQ_UNLOCK()	mtx_unlock(&crypto_ret_q_mtx)
82158826Spjd#define	CRYPTO_RETQ_EMPTY()	(TAILQ_EMPTY(&crp_ret_q) && TAILQ_EMPTY(&crp_ret_kq))
83104476Ssam
84104476Ssamstatic	uma_zone_t cryptop_zone;
85104476Ssamstatic	uma_zone_t cryptodesc_zone;
86104476Ssam
87104476Ssamint	crypto_userasymcrypto = 1;	/* userland may do asym crypto reqs */
88104476SsamSYSCTL_INT(_kern, OID_AUTO, userasymcrypto, CTLFLAG_RW,
89104476Ssam	   &crypto_userasymcrypto, 0,
90104476Ssam	   "Enable/disable user-mode access to asymmetric crypto support");
91104476Ssamint	crypto_devallowsoft = 0;	/* only use hardware crypto for asym */
92104476SsamSYSCTL_INT(_kern, OID_AUTO, cryptodevallowsoft, CTLFLAG_RW,
93104476Ssam	   &crypto_devallowsoft, 0,
94104476Ssam	   "Enable/disable use of software asym crypto support");
95104476Ssam
96104476SsamMALLOC_DEFINE(M_CRYPTO_DATA, "crypto", "crypto session records");
97104476Ssam
98108588Ssamstatic	void crypto_proc(void);
99108588Ssamstatic	struct proc *cryptoproc;
100108588Ssamstatic	void crypto_ret_proc(void);
101108588Ssamstatic	struct proc *cryptoretproc;
102108588Ssamstatic	void crypto_destroy(void);
103158702Spjdstatic	int crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint);
104158702Spjdstatic	int crypto_kinvoke(struct cryptkop *krp);
105108588Ssam
106108587Ssamstatic	struct cryptostats cryptostats;
107108587SsamSYSCTL_STRUCT(_kern, OID_AUTO, crypto_stats, CTLFLAG_RW, &cryptostats,
108108587Ssam	    cryptostats, "Crypto system statistics");
109108587Ssam
110108587Ssam#ifdef CRYPTO_TIMING
111108587Ssamstatic	int crypto_timing = 0;
112108587SsamSYSCTL_INT(_debug, OID_AUTO, crypto_timing, CTLFLAG_RW,
113108587Ssam	   &crypto_timing, 0, "Enable/disable crypto timing support");
114108587Ssam#endif
115108587Ssam
116108588Ssamstatic int
117104476Ssamcrypto_init(void)
118104476Ssam{
119108588Ssam	int error;
120108588Ssam
121115746Ssam	mtx_init(&crypto_drivers_mtx, "crypto", "crypto driver table",
122115746Ssam		MTX_DEF|MTX_QUIET);
123108588Ssam
124108588Ssam	TAILQ_INIT(&crp_q);
125108588Ssam	TAILQ_INIT(&crp_kq);
126115746Ssam	mtx_init(&crypto_q_mtx, "crypto", "crypto op queues", MTX_DEF);
127108588Ssam
128108588Ssam	TAILQ_INIT(&crp_ret_q);
129108588Ssam	TAILQ_INIT(&crp_ret_kq);
130115746Ssam	mtx_init(&crypto_ret_q_mtx, "crypto", "crypto return queues", MTX_DEF);
131108588Ssam
132104476Ssam	cryptop_zone = uma_zcreate("cryptop", sizeof (struct cryptop),
133104476Ssam				    0, 0, 0, 0,
134104476Ssam				    UMA_ALIGN_PTR, UMA_ZONE_ZINIT);
135104476Ssam	cryptodesc_zone = uma_zcreate("cryptodesc", sizeof (struct cryptodesc),
136104476Ssam				    0, 0, 0, 0,
137104476Ssam				    UMA_ALIGN_PTR, UMA_ZONE_ZINIT);
138108588Ssam	if (cryptodesc_zone == NULL || cryptop_zone == NULL) {
139108588Ssam		printf("crypto_init: cannot setup crypto zones\n");
140108588Ssam		error = ENOMEM;
141108588Ssam		goto bad;
142108588Ssam	}
143104476Ssam
144104476Ssam	crypto_drivers_num = CRYPTO_DRIVERS_INITIAL;
145104476Ssam	crypto_drivers = malloc(crypto_drivers_num *
146104476Ssam	    sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT | M_ZERO);
147108588Ssam	if (crypto_drivers == NULL) {
148108588Ssam		printf("crypto_init: cannot setup crypto drivers\n");
149108588Ssam		error = ENOMEM;
150108588Ssam		goto bad;
151108588Ssam	}
152104476Ssam
153108588Ssam	error = kthread_create((void (*)(void *)) crypto_proc, NULL,
154108588Ssam		    &cryptoproc, 0, 0, "crypto");
155108588Ssam	if (error) {
156108588Ssam		printf("crypto_init: cannot start crypto thread; error %d",
157108588Ssam			error);
158108588Ssam		goto bad;
159108588Ssam	}
160104476Ssam
161108588Ssam	error = kthread_create((void (*)(void *)) crypto_ret_proc, NULL,
162108588Ssam		    &cryptoretproc, 0, 0, "crypto returns");
163108588Ssam	if (error) {
164108588Ssam		printf("crypto_init: cannot start cryptoret thread; error %d",
165108588Ssam			error);
166108588Ssam		goto bad;
167108588Ssam	}
168108588Ssam	return 0;
169108588Ssambad:
170108588Ssam	crypto_destroy();
171108588Ssam	return error;
172104476Ssam}
173104476Ssam
174104476Ssam/*
175108588Ssam * Signal a crypto thread to terminate.  We use the driver
176108588Ssam * table lock to synchronize the sleep/wakeups so that we
177108588Ssam * are sure the threads have terminated before we release
178108588Ssam * the data structures they use.  See crypto_finis below
179108588Ssam * for the other half of this song-and-dance.
180108588Ssam */
181108588Ssamstatic void
182108588Ssamcrypto_terminate(struct proc **pp, void *q)
183108588Ssam{
184108588Ssam	struct proc *p;
185108588Ssam
186108588Ssam	mtx_assert(&crypto_drivers_mtx, MA_OWNED);
187108588Ssam	p = *pp;
188108588Ssam	*pp = NULL;
189108588Ssam	if (p) {
190108588Ssam		wakeup_one(q);
191108588Ssam		PROC_LOCK(p);		/* NB: insure we don't miss wakeup */
192108588Ssam		CRYPTO_DRIVER_UNLOCK();	/* let crypto_finis progress */
193108588Ssam		msleep(p, &p->p_mtx, PWAIT, "crypto_destroy", 0);
194108588Ssam		PROC_UNLOCK(p);
195108588Ssam		CRYPTO_DRIVER_LOCK();
196108588Ssam	}
197108588Ssam}
198108588Ssam
199108588Ssamstatic void
200108588Ssamcrypto_destroy(void)
201108588Ssam{
202108588Ssam	/*
203108588Ssam	 * Terminate any crypto threads.
204108588Ssam	 */
205108588Ssam	CRYPTO_DRIVER_LOCK();
206108588Ssam	crypto_terminate(&cryptoproc, &crp_q);
207108588Ssam	crypto_terminate(&cryptoretproc, &crp_ret_q);
208108588Ssam	CRYPTO_DRIVER_UNLOCK();
209108588Ssam
210108588Ssam	/* XXX flush queues??? */
211108588Ssam
212108588Ssam	/*
213108588Ssam	 * Reclaim dynamically allocated resources.
214108588Ssam	 */
215108588Ssam	if (crypto_drivers != NULL)
216108588Ssam		free(crypto_drivers, M_CRYPTO_DATA);
217108588Ssam
218108588Ssam	if (cryptodesc_zone != NULL)
219108588Ssam		uma_zdestroy(cryptodesc_zone);
220108588Ssam	if (cryptop_zone != NULL)
221108588Ssam		uma_zdestroy(cryptop_zone);
222108588Ssam	mtx_destroy(&crypto_q_mtx);
223108588Ssam	mtx_destroy(&crypto_ret_q_mtx);
224108588Ssam	mtx_destroy(&crypto_drivers_mtx);
225108588Ssam}
226108588Ssam
227108588Ssam/*
228105251Smarkm * Initialization code, both for static and dynamic loading.
229105251Smarkm */
230105251Smarkmstatic int
231105251Smarkmcrypto_modevent(module_t mod, int type, void *unused)
232105251Smarkm{
233108588Ssam	int error = EINVAL;
234108588Ssam
235105251Smarkm	switch (type) {
236105251Smarkm	case MOD_LOAD:
237108588Ssam		error = crypto_init();
238108588Ssam		if (error == 0 && bootverbose)
239105251Smarkm			printf("crypto: <crypto core>\n");
240108588Ssam		break;
241105251Smarkm	case MOD_UNLOAD:
242105251Smarkm		/*XXX disallow if active sessions */
243108588Ssam		error = 0;
244108588Ssam		crypto_destroy();
245105251Smarkm		return 0;
246105251Smarkm	}
247108588Ssam	return error;
248105251Smarkm}
249105251Smarkm
250105251Smarkmstatic moduledata_t crypto_mod = {
251105251Smarkm	"crypto",
252105251Smarkm	crypto_modevent,
253105251Smarkm	0
254105251Smarkm};
255105251SmarkmMODULE_VERSION(crypto, 1);
256106676SsamDECLARE_MODULE(crypto, crypto_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
257156281SwkoszekMODULE_DEPEND(crypto, zlib, 1, 1, 1);
258105251Smarkm
259105251Smarkm/*
260104476Ssam * Create a new session.
261104476Ssam */
262104476Ssamint
263104476Ssamcrypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard)
264104476Ssam{
265159240Spjd	struct cryptocap *cap = NULL;
266104476Ssam	struct cryptoini *cr;
267159240Spjd	u_int32_t hid = 0, lid;
268104476Ssam	int err = EINVAL;
269104476Ssam
270104476Ssam	CRYPTO_DRIVER_LOCK();
271104476Ssam
272104476Ssam	if (crypto_drivers == NULL)
273104476Ssam		goto done;
274104476Ssam
275104476Ssam	/*
276104476Ssam	 * The algorithm we use here is pretty stupid; just use the
277104476Ssam	 * first driver that supports all the algorithms we need.
278104476Ssam	 *
279104476Ssam	 * XXX We need more smarts here (in real life too, but that's
280104476Ssam	 * XXX another story altogether).
281104476Ssam	 */
282104476Ssam
283159240Spjd	/*
284159240Spjd	 * First try to find hardware crypto.
285159240Spjd	 */
286159240Spjd	if (hard >= 0) {
287159240Spjd		for (hid = 0; hid < crypto_drivers_num; hid++) {
288159240Spjd			cap = &crypto_drivers[hid];
289159240Spjd			/*
290159240Spjd			 * If it's not initialized or has remaining sessions
291159240Spjd			 * referencing it, skip.
292159240Spjd			 */
293159240Spjd			if (cap->cc_newsession == NULL ||
294159240Spjd			    (cap->cc_flags & CRYPTOCAP_F_CLEANUP))
295159240Spjd				continue;
296104476Ssam
297159240Spjd			/* Hardware required -- ignore software drivers. */
298159240Spjd			if (cap->cc_flags & CRYPTOCAP_F_SOFTWARE)
299159240Spjd				continue;
300104476Ssam
301159240Spjd			/* See if all the algorithms are supported. */
302159240Spjd			for (cr = cri; cr; cr = cr->cri_next)
303159240Spjd				if (cap->cc_alg[cr->cri_alg] == 0)
304159240Spjd					break;
305159240Spjd			if (cr == NULL) {
306159240Spjd				/* Ok, all algorithms are supported. */
307104476Ssam				break;
308159240Spjd			}
309159240Spjd		}
310159240Spjd		if (hid == crypto_drivers_num)
311159240Spjd			cap = NULL;
312159240Spjd	}
313159240Spjd	/*
314159240Spjd	 * If no hardware crypto, look for software crypto.
315159240Spjd	 */
316159240Spjd	if (cap == NULL && hard <= 0) {
317159240Spjd		for (hid = 0; hid < crypto_drivers_num; hid++) {
318159240Spjd			cap = &crypto_drivers[hid];
319104476Ssam			/*
320159240Spjd			 * If it's not initialized or has remaining sessions
321159240Spjd			 * referencing it, skip.
322104476Ssam			 */
323159240Spjd			if (cap->cc_newsession == NULL ||
324159240Spjd			    (cap->cc_flags & CRYPTOCAP_F_CLEANUP))
325159240Spjd				continue;
326104476Ssam
327159240Spjd			/* Software required -- ignore hardware drivers. */
328159240Spjd			if (!(cap->cc_flags & CRYPTOCAP_F_SOFTWARE))
329159240Spjd				continue;
330159240Spjd
331159240Spjd			/* See if all the algorithms are supported. */
332159240Spjd			for (cr = cri; cr; cr = cr->cri_next)
333159240Spjd				if (cap->cc_alg[cr->cri_alg] == 0)
334159240Spjd					break;
335159240Spjd			if (cr == NULL) {
336159240Spjd				/* Ok, all algorithms are supported. */
337159240Spjd				break;
338104476Ssam			}
339104476Ssam		}
340159240Spjd		if (hid == crypto_drivers_num)
341159240Spjd			cap = NULL;
342104476Ssam	}
343159240Spjd
344159240Spjd	if (cap != NULL) {
345159240Spjd		/*
346159240Spjd		 * Can't do everything in one session.
347159240Spjd		 *
348159240Spjd		 * XXX Fix this. We need to inject a "virtual" session layer right
349159240Spjd		 * XXX about here.
350159240Spjd		 */
351159240Spjd
352159240Spjd		/* Call the driver initialization routine. */
353159240Spjd		lid = hid;		/* Pass the driver ID. */
354159240Spjd		err = (*cap->cc_newsession)(cap->cc_arg, &lid, cri);
355159240Spjd		if (err == 0) {
356159240Spjd			/* XXX assert (hid &~ 0xffffff) == 0 */
357159240Spjd			/* XXX assert (cap->cc_flags &~ 0xff) == 0 */
358159240Spjd			(*sid) = ((cap->cc_flags & 0xff) << 24) | hid;
359159240Spjd			(*sid) <<= 32;
360159240Spjd			(*sid) |= (lid & 0xffffffff);
361159240Spjd			cap->cc_sessions++;
362159240Spjd		}
363159240Spjd	}
364104476Ssamdone:
365104476Ssam	CRYPTO_DRIVER_UNLOCK();
366104476Ssam	return err;
367104476Ssam}
368104476Ssam
369158702Spjdstatic void
370158702Spjdcrypto_remove(struct cryptocap *cap)
371158702Spjd{
372158702Spjd
373158702Spjd	mtx_assert(&crypto_drivers_mtx, MA_OWNED);
374158702Spjd	if (cap->cc_sessions == 0 && cap->cc_koperations == 0)
375158702Spjd		bzero(cap, sizeof(*cap));
376158702Spjd}
377158702Spjd
378104476Ssam/*
379104476Ssam * Delete an existing session (or a reserved session on an unregistered
380104476Ssam * driver).
381104476Ssam */
382104476Ssamint
383104476Ssamcrypto_freesession(u_int64_t sid)
384104476Ssam{
385158702Spjd	struct cryptocap *cap;
386104476Ssam	u_int32_t hid;
387104476Ssam	int err;
388104476Ssam
389104476Ssam	CRYPTO_DRIVER_LOCK();
390104476Ssam
391104476Ssam	if (crypto_drivers == NULL) {
392104476Ssam		err = EINVAL;
393104476Ssam		goto done;
394104476Ssam	}
395104476Ssam
396104476Ssam	/* Determine two IDs. */
397116924Ssam	hid = CRYPTO_SESID2HID(sid);
398104476Ssam
399104476Ssam	if (hid >= crypto_drivers_num) {
400104476Ssam		err = ENOENT;
401104476Ssam		goto done;
402104476Ssam	}
403158702Spjd	cap = &crypto_drivers[hid];
404104476Ssam
405158702Spjd	if (cap->cc_sessions)
406158702Spjd		cap->cc_sessions--;
407104476Ssam
408104476Ssam	/* Call the driver cleanup routine, if available. */
409158702Spjd	if (cap->cc_freesession)
410158702Spjd		err = cap->cc_freesession(cap->cc_arg, sid);
411104476Ssam	else
412104476Ssam		err = 0;
413104476Ssam
414158702Spjd	if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
415158702Spjd		crypto_remove(cap);
416104476Ssam
417104476Ssamdone:
418104476Ssam	CRYPTO_DRIVER_UNLOCK();
419104476Ssam	return err;
420104476Ssam}
421104476Ssam
422104476Ssam/*
423104476Ssam * Return an unused driver id.  Used by drivers prior to registering
424104476Ssam * support for the algorithms they handle.
425104476Ssam */
426104476Ssamint32_t
427104476Ssamcrypto_get_driverid(u_int32_t flags)
428104476Ssam{
429104476Ssam	struct cryptocap *newdrv;
430104476Ssam	int i;
431104476Ssam
432104476Ssam	CRYPTO_DRIVER_LOCK();
433104476Ssam
434158702Spjd	for (i = 0; i < crypto_drivers_num; i++) {
435104476Ssam		if (crypto_drivers[i].cc_process == NULL &&
436158702Spjd		    (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0) {
437104476Ssam			break;
438158702Spjd		}
439158702Spjd	}
440104476Ssam
441104476Ssam	/* Out of entries, allocate some more. */
442104476Ssam	if (i == crypto_drivers_num) {
443104476Ssam		/* Be careful about wrap-around. */
444104476Ssam		if (2 * crypto_drivers_num <= crypto_drivers_num) {
445104476Ssam			CRYPTO_DRIVER_UNLOCK();
446104476Ssam			printf("crypto: driver count wraparound!\n");
447104476Ssam			return -1;
448104476Ssam		}
449104476Ssam
450104476Ssam		newdrv = malloc(2 * crypto_drivers_num *
451104476Ssam		    sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
452104476Ssam		if (newdrv == NULL) {
453104476Ssam			CRYPTO_DRIVER_UNLOCK();
454104476Ssam			printf("crypto: no space to expand driver table!\n");
455104476Ssam			return -1;
456104476Ssam		}
457104476Ssam
458104476Ssam		bcopy(crypto_drivers, newdrv,
459104476Ssam		    crypto_drivers_num * sizeof(struct cryptocap));
460104476Ssam
461104476Ssam		crypto_drivers_num *= 2;
462104476Ssam
463104476Ssam		free(crypto_drivers, M_CRYPTO_DATA);
464104476Ssam		crypto_drivers = newdrv;
465104476Ssam	}
466104476Ssam
467104476Ssam	/* NB: state is zero'd on free */
468104476Ssam	crypto_drivers[i].cc_sessions = 1;	/* Mark */
469104476Ssam	crypto_drivers[i].cc_flags = flags;
470104476Ssam	if (bootverbose)
471104476Ssam		printf("crypto: assign driver %u, flags %u\n", i, flags);
472104476Ssam
473104476Ssam	CRYPTO_DRIVER_UNLOCK();
474104476Ssam
475104476Ssam	return i;
476104476Ssam}
477104476Ssam
478104476Ssamstatic struct cryptocap *
479104476Ssamcrypto_checkdriver(u_int32_t hid)
480104476Ssam{
481104476Ssam	if (crypto_drivers == NULL)
482104476Ssam		return NULL;
483104476Ssam	return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]);
484104476Ssam}
485104476Ssam
486104476Ssam/*
487104476Ssam * Register support for a key-related algorithm.  This routine
488104476Ssam * is called once for each algorithm supported a driver.
489104476Ssam */
490104476Ssamint
491104476Ssamcrypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags,
492104476Ssam    int (*kprocess)(void*, struct cryptkop *, int),
493104476Ssam    void *karg)
494104476Ssam{
495104476Ssam	struct cryptocap *cap;
496104476Ssam	int err;
497104476Ssam
498104476Ssam	CRYPTO_DRIVER_LOCK();
499104476Ssam
500104476Ssam	cap = crypto_checkdriver(driverid);
501104476Ssam	if (cap != NULL &&
502104476Ssam	    (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) {
503104476Ssam		/*
504104476Ssam		 * XXX Do some performance testing to determine placing.
505104476Ssam		 * XXX We probably need an auxiliary data structure that
506104476Ssam		 * XXX describes relative performances.
507104476Ssam		 */
508104476Ssam
509104476Ssam		cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
510104476Ssam		if (bootverbose)
511104476Ssam			printf("crypto: driver %u registers key alg %u flags %u\n"
512104476Ssam				, driverid
513104476Ssam				, kalg
514104476Ssam				, flags
515104476Ssam			);
516104476Ssam
517104476Ssam		if (cap->cc_kprocess == NULL) {
518104476Ssam			cap->cc_karg = karg;
519104476Ssam			cap->cc_kprocess = kprocess;
520104476Ssam		}
521104476Ssam		err = 0;
522104476Ssam	} else
523104476Ssam		err = EINVAL;
524104476Ssam
525104476Ssam	CRYPTO_DRIVER_UNLOCK();
526104476Ssam	return err;
527104476Ssam}
528104476Ssam
529104476Ssam/*
530104476Ssam * Register support for a non-key-related algorithm.  This routine
531104476Ssam * is called once for each such algorithm supported by a driver.
532104476Ssam */
533104476Ssamint
534104476Ssamcrypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
535104476Ssam    u_int32_t flags,
536104476Ssam    int (*newses)(void*, u_int32_t*, struct cryptoini*),
537104476Ssam    int (*freeses)(void*, u_int64_t),
538104476Ssam    int (*process)(void*, struct cryptop *, int),
539104476Ssam    void *arg)
540104476Ssam{
541104476Ssam	struct cryptocap *cap;
542104476Ssam	int err;
543104476Ssam
544104476Ssam	CRYPTO_DRIVER_LOCK();
545104476Ssam
546104476Ssam	cap = crypto_checkdriver(driverid);
547104476Ssam	/* NB: algorithms are in the range [1..max] */
548104476Ssam	if (cap != NULL &&
549104476Ssam	    (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) {
550104476Ssam		/*
551104476Ssam		 * XXX Do some performance testing to determine placing.
552104476Ssam		 * XXX We probably need an auxiliary data structure that
553104476Ssam		 * XXX describes relative performances.
554104476Ssam		 */
555104476Ssam
556104476Ssam		cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
557104476Ssam		cap->cc_max_op_len[alg] = maxoplen;
558104476Ssam		if (bootverbose)
559104476Ssam			printf("crypto: driver %u registers alg %u flags %u maxoplen %u\n"
560104476Ssam				, driverid
561104476Ssam				, alg
562104476Ssam				, flags
563104476Ssam				, maxoplen
564104476Ssam			);
565104476Ssam
566104476Ssam		if (cap->cc_process == NULL) {
567104476Ssam			cap->cc_arg = arg;
568104476Ssam			cap->cc_newsession = newses;
569104476Ssam			cap->cc_process = process;
570104476Ssam			cap->cc_freesession = freeses;
571104476Ssam			cap->cc_sessions = 0;		/* Unmark */
572104476Ssam		}
573104476Ssam		err = 0;
574104476Ssam	} else
575104476Ssam		err = EINVAL;
576104476Ssam
577104476Ssam	CRYPTO_DRIVER_UNLOCK();
578104476Ssam	return err;
579104476Ssam}
580104476Ssam
581104476Ssam/*
582104476Ssam * Unregister a crypto driver. If there are pending sessions using it,
583104476Ssam * leave enough information around so that subsequent calls using those
584104476Ssam * sessions will correctly detect the driver has been unregistered and
585104476Ssam * reroute requests.
586104476Ssam */
587104476Ssamint
588104476Ssamcrypto_unregister(u_int32_t driverid, int alg)
589104476Ssam{
590158702Spjd	struct cryptocap *cap;
591158702Spjd	u_int32_t ses, kops;
592104476Ssam	int i, err;
593104476Ssam
594104476Ssam	CRYPTO_DRIVER_LOCK();
595104476Ssam
596104476Ssam	cap = crypto_checkdriver(driverid);
597104476Ssam	if (cap != NULL &&
598104476Ssam	    (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) &&
599104476Ssam	    cap->cc_alg[alg] != 0) {
600104476Ssam		cap->cc_alg[alg] = 0;
601104476Ssam		cap->cc_max_op_len[alg] = 0;
602104476Ssam
603104476Ssam		/* Was this the last algorithm ? */
604104476Ssam		for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
605104476Ssam			if (cap->cc_alg[i] != 0)
606104476Ssam				break;
607104476Ssam
608104476Ssam		if (i == CRYPTO_ALGORITHM_MAX + 1) {
609104476Ssam			ses = cap->cc_sessions;
610158702Spjd			kops = cap->cc_koperations;
611158702Spjd			bzero(cap, sizeof(*cap));
612158702Spjd			if (ses != 0 || kops != 0) {
613104476Ssam				/*
614104476Ssam				 * If there are pending sessions, just mark as invalid.
615104476Ssam				 */
616104476Ssam				cap->cc_flags |= CRYPTOCAP_F_CLEANUP;
617104476Ssam				cap->cc_sessions = ses;
618158702Spjd				cap->cc_koperations = kops;
619104476Ssam			}
620104476Ssam		}
621104476Ssam		err = 0;
622104476Ssam	} else
623104476Ssam		err = EINVAL;
624104476Ssam
625104476Ssam	CRYPTO_DRIVER_UNLOCK();
626104476Ssam	return err;
627104476Ssam}
628104476Ssam
629104476Ssam/*
630104476Ssam * Unregister all algorithms associated with a crypto driver.
631104476Ssam * If there are pending sessions using it, leave enough information
632104476Ssam * around so that subsequent calls using those sessions will
633104476Ssam * correctly detect the driver has been unregistered and reroute
634104476Ssam * requests.
635104476Ssam */
636104476Ssamint
637104476Ssamcrypto_unregister_all(u_int32_t driverid)
638104476Ssam{
639158702Spjd	struct cryptocap *cap;
640158702Spjd	u_int32_t ses, kops;
641104476Ssam	int i, err;
642104476Ssam
643104476Ssam	CRYPTO_DRIVER_LOCK();
644104476Ssam
645104476Ssam	cap = crypto_checkdriver(driverid);
646104476Ssam	if (cap != NULL) {
647104476Ssam		for (i = CRYPTO_ALGORITHM_MIN; i <= CRYPTO_ALGORITHM_MAX; i++) {
648104476Ssam			cap->cc_alg[i] = 0;
649104476Ssam			cap->cc_max_op_len[i] = 0;
650104476Ssam		}
651104476Ssam		ses = cap->cc_sessions;
652158702Spjd		kops = cap->cc_koperations;
653158702Spjd		bzero(cap, sizeof(*cap));
654158702Spjd		if (ses != 0 || kops != 0) {
655104476Ssam			/*
656104476Ssam			 * If there are pending sessions, just mark as invalid.
657104476Ssam			 */
658104476Ssam			cap->cc_flags |= CRYPTOCAP_F_CLEANUP;
659104476Ssam			cap->cc_sessions = ses;
660158702Spjd			cap->cc_koperations = kops;
661104476Ssam		}
662104476Ssam		err = 0;
663104476Ssam	} else
664104476Ssam		err = EINVAL;
665104476Ssam
666104476Ssam	CRYPTO_DRIVER_UNLOCK();
667104476Ssam	return err;
668104476Ssam}
669104476Ssam
670104476Ssam/*
671104476Ssam * Clear blockage on a driver.  The what parameter indicates whether
672104476Ssam * the driver is now ready for cryptop's and/or cryptokop's.
673104476Ssam */
674104476Ssamint
675104476Ssamcrypto_unblock(u_int32_t driverid, int what)
676104476Ssam{
677104476Ssam	struct cryptocap *cap;
678158827Spjd	int err;
679104476Ssam
680104476Ssam	CRYPTO_Q_LOCK();
681104476Ssam	cap = crypto_checkdriver(driverid);
682104476Ssam	if (cap != NULL) {
683158827Spjd		if (what & CRYPTO_SYMQ)
684104476Ssam			cap->cc_qblocked = 0;
685158827Spjd		if (what & CRYPTO_ASYMQ)
686104476Ssam			cap->cc_kqblocked = 0;
687158827Spjd		if (crp_sleep)
688104628Ssam			wakeup_one(&crp_q);
689104476Ssam		err = 0;
690104476Ssam	} else
691104476Ssam		err = EINVAL;
692104476Ssam	CRYPTO_Q_UNLOCK();
693104476Ssam
694104476Ssam	return err;
695104476Ssam}
696104476Ssam
697104476Ssam/*
698104476Ssam * Add a crypto request to a queue, to be processed by the kernel thread.
699104476Ssam */
700104476Ssamint
701104476Ssamcrypto_dispatch(struct cryptop *crp)
702104476Ssam{
703158702Spjd	struct cryptocap *cap;
704158702Spjd	u_int32_t hid;
705158702Spjd	int result;
706104476Ssam
707108587Ssam	cryptostats.cs_ops++;
708108587Ssam
709108587Ssam#ifdef CRYPTO_TIMING
710108587Ssam	if (crypto_timing)
711108587Ssam		binuptime(&crp->crp_tstamp);
712108587Ssam#endif
713108587Ssam
714158702Spjd	hid = CRYPTO_SESID2HID(crp->crp_sid);
715158702Spjd
716111297Ssam	if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) {
717111297Ssam		/*
718111297Ssam		 * Caller marked the request to be processed
719111297Ssam		 * immediately; dispatch it directly to the
720111297Ssam		 * driver unless the driver is currently blocked.
721111297Ssam		 */
722111297Ssam		cap = crypto_checkdriver(hid);
723158702Spjd		/* Driver cannot disappeared when there is an active session. */
724158702Spjd		KASSERT(cap != NULL, ("%s: Driver disappeared.", __func__));
725158702Spjd		if (!cap->cc_qblocked) {
726158702Spjd			result = crypto_invoke(cap, crp, 0);
727158702Spjd			if (result != ERESTART)
728158702Spjd				return (result);
729158823Spjd			/*
730158823Spjd			 * The driver ran out of resources, put the request on
731158823Spjd			 * the queue.
732158823Spjd			 */
733108990Ssam		}
734108990Ssam	}
735158702Spjd	CRYPTO_Q_LOCK();
736158827Spjd	TAILQ_INSERT_TAIL(&crp_q, crp, crp_next);
737158827Spjd	if (crp_sleep)
738157665Spjd		wakeup_one(&crp_q);
739115746Ssam	CRYPTO_Q_UNLOCK();
740158702Spjd	return 0;
741104476Ssam}
742104476Ssam
743104476Ssam/*
744104476Ssam * Add an asymetric crypto request to a queue,
745104476Ssam * to be processed by the kernel thread.
746104476Ssam */
747104476Ssamint
748104476Ssamcrypto_kdispatch(struct cryptkop *krp)
749104476Ssam{
750158702Spjd	int result;
751104476Ssam
752108587Ssam	cryptostats.cs_kops++;
753108587Ssam
754158702Spjd	result = crypto_kinvoke(krp);
755158702Spjd	if (result != ERESTART)
756158702Spjd		return (result);
757104476Ssam	CRYPTO_Q_LOCK();
758158827Spjd	TAILQ_INSERT_TAIL(&crp_kq, krp, krp_next);
759158827Spjd	if (crp_sleep)
760157665Spjd		wakeup_one(&crp_q);
761104476Ssam	CRYPTO_Q_UNLOCK();
762104476Ssam
763158702Spjd	return 0;
764104476Ssam}
765104476Ssam
766104476Ssam/*
767104476Ssam * Dispatch an assymetric crypto request to the appropriate crypto devices.
768104476Ssam */
769104476Ssamstatic int
770158702Spjdcrypto_kinvoke(struct cryptkop *krp)
771104476Ssam{
772158702Spjd	struct cryptocap *cap = NULL;
773104476Ssam	u_int32_t hid;
774158702Spjd	int error = 0;
775104476Ssam
776158702Spjd	KASSERT(krp != NULL, ("%s: krp == NULL", __func__));
777158702Spjd	KASSERT(krp->krp_callback != NULL,
778158702Spjd	    ("%s: krp->crp_callback == NULL", __func__));
779104476Ssam
780158702Spjd	CRYPTO_DRIVER_LOCK();
781104476Ssam	for (hid = 0; hid < crypto_drivers_num; hid++) {
782158702Spjd		cap = &crypto_drivers[hid];
783158702Spjd		if (cap == NULL)
784104476Ssam			continue;
785158702Spjd		if ((cap->cc_flags & CRYPTOCAP_F_SOFTWARE) &&
786158702Spjd		    !crypto_devallowsoft) {
787104476Ssam			continue;
788158702Spjd		}
789158702Spjd		if (cap->cc_kprocess == NULL)
790104476Ssam			continue;
791158702Spjd		if (!(cap->cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED))
792158702Spjd			continue;
793158702Spjd		if (cap->cc_kqblocked) {
794158702Spjd			error = ERESTART;
795158702Spjd			continue;
796158702Spjd		}
797158702Spjd		error = 0;
798104476Ssam		break;
799104476Ssam	}
800158702Spjd	krp->krp_hid = hid;
801104476Ssam	if (hid < crypto_drivers_num) {
802158702Spjd		cap->cc_koperations++;
803158702Spjd		CRYPTO_DRIVER_UNLOCK();
804158702Spjd		error = cap->cc_kprocess(cap->cc_karg, krp, 0);
805158702Spjd		CRYPTO_DRIVER_LOCK();
806158702Spjd		if (error == ERESTART) {
807158702Spjd			cap->cc_koperations--;
808158702Spjd			CRYPTO_DRIVER_UNLOCK();
809158702Spjd			return (error);
810158702Spjd		}
811158702Spjd	} else {
812104476Ssam		error = ENODEV;
813158702Spjd	}
814158702Spjd	CRYPTO_DRIVER_UNLOCK();
815104476Ssam
816104476Ssam	if (error) {
817104476Ssam		krp->krp_status = error;
818104628Ssam		crypto_kdone(krp);
819104476Ssam	}
820104476Ssam	return 0;
821104476Ssam}
822104476Ssam
823108587Ssam#ifdef CRYPTO_TIMING
824108587Ssamstatic void
825108587Ssamcrypto_tstat(struct cryptotstat *ts, struct bintime *bt)
826108587Ssam{
827108587Ssam	struct bintime now, delta;
828108587Ssam	struct timespec t;
829108587Ssam	uint64_t u;
830108587Ssam
831108587Ssam	binuptime(&now);
832108587Ssam	u = now.frac;
833108587Ssam	delta.frac = now.frac - bt->frac;
834108587Ssam	delta.sec = now.sec - bt->sec;
835108587Ssam	if (u < delta.frac)
836108587Ssam		delta.sec--;
837108587Ssam	bintime2timespec(&delta, &t);
838108587Ssam	timespecadd(&ts->acc, &t);
839108587Ssam	if (timespeccmp(&t, &ts->min, <))
840108587Ssam		ts->min = t;
841108587Ssam	if (timespeccmp(&t, &ts->max, >))
842108587Ssam		ts->max = t;
843108587Ssam	ts->count++;
844108587Ssam
845108587Ssam	*bt = now;
846108587Ssam}
847108587Ssam#endif
848108587Ssam
849104476Ssam/*
850104476Ssam * Dispatch a crypto request to the appropriate crypto devices.
851104476Ssam */
852104476Ssamstatic int
853158702Spjdcrypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint)
854104476Ssam{
855104476Ssam
856158702Spjd	KASSERT(crp != NULL, ("%s: crp == NULL", __func__));
857158702Spjd	KASSERT(crp->crp_callback != NULL,
858158702Spjd	    ("%s: crp->crp_callback == NULL", __func__));
859158702Spjd	KASSERT(crp->crp_desc != NULL, ("%s: crp->crp_desc == NULL", __func__));
860158702Spjd
861108587Ssam#ifdef CRYPTO_TIMING
862108587Ssam	if (crypto_timing)
863108587Ssam		crypto_tstat(&cryptostats.cs_invoke, &crp->crp_tstamp);
864108587Ssam#endif
865158702Spjd	if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) {
866104476Ssam		struct cryptodesc *crd;
867104476Ssam		u_int64_t nid;
868104476Ssam
869104476Ssam		/*
870104476Ssam		 * Driver has unregistered; migrate the session and return
871104476Ssam		 * an error to the caller so they'll resubmit the op.
872158702Spjd		 *
873158702Spjd		 * XXX: What if there are more already queued requests for this
874158702Spjd		 *      session?
875104476Ssam		 */
876158702Spjd		crypto_freesession(crp->crp_sid);
877158702Spjd
878104476Ssam		for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
879104476Ssam			crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
880104476Ssam
881104476Ssam		if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0)
882104476Ssam			crp->crp_sid = nid;
883104476Ssam
884104476Ssam		crp->crp_etype = EAGAIN;
885104628Ssam		crypto_done(crp);
886104476Ssam		return 0;
887104476Ssam	} else {
888104476Ssam		/*
889104476Ssam		 * Invoke the driver to process the request.
890104476Ssam		 */
891158702Spjd		return cap->cc_process(cap->cc_arg, crp, hint);
892104476Ssam	}
893104476Ssam}
894104476Ssam
895104476Ssam/*
896104476Ssam * Release a set of crypto descriptors.
897104476Ssam */
898104476Ssamvoid
899104476Ssamcrypto_freereq(struct cryptop *crp)
900104476Ssam{
901104476Ssam	struct cryptodesc *crd;
902104476Ssam
903104476Ssam	if (crp == NULL)
904104476Ssam		return;
905104476Ssam
906104476Ssam	while ((crd = crp->crp_desc) != NULL) {
907104476Ssam		crp->crp_desc = crd->crd_next;
908104476Ssam		uma_zfree(cryptodesc_zone, crd);
909104476Ssam	}
910104476Ssam
911104476Ssam	uma_zfree(cryptop_zone, crp);
912104476Ssam}
913104476Ssam
914104476Ssam/*
915104476Ssam * Acquire a set of crypto descriptors.
916104476Ssam */
917104476Ssamstruct cryptop *
918104476Ssamcrypto_getreq(int num)
919104476Ssam{
920104476Ssam	struct cryptodesc *crd;
921104476Ssam	struct cryptop *crp;
922104476Ssam
923108813Ssam	crp = uma_zalloc(cryptop_zone, M_NOWAIT|M_ZERO);
924104476Ssam	if (crp != NULL) {
925104476Ssam		while (num--) {
926108813Ssam			crd = uma_zalloc(cryptodesc_zone, M_NOWAIT|M_ZERO);
927104476Ssam			if (crd == NULL) {
928104476Ssam				crypto_freereq(crp);
929104476Ssam				return NULL;
930104476Ssam			}
931104476Ssam
932104476Ssam			crd->crd_next = crp->crp_desc;
933104476Ssam			crp->crp_desc = crd;
934104476Ssam		}
935104476Ssam	}
936104476Ssam	return crp;
937104476Ssam}
938104476Ssam
939104476Ssam/*
940104476Ssam * Invoke the callback on behalf of the driver.
941104476Ssam */
942104476Ssamvoid
943104476Ssamcrypto_done(struct cryptop *crp)
944104476Ssam{
945115746Ssam	KASSERT((crp->crp_flags & CRYPTO_F_DONE) == 0,
946115746Ssam		("crypto_done: op already done, flags 0x%x", crp->crp_flags));
947115746Ssam	crp->crp_flags |= CRYPTO_F_DONE;
948108587Ssam	if (crp->crp_etype != 0)
949108587Ssam		cryptostats.cs_errs++;
950108587Ssam#ifdef CRYPTO_TIMING
951108587Ssam	if (crypto_timing)
952108587Ssam		crypto_tstat(&cryptostats.cs_done, &crp->crp_tstamp);
953108587Ssam#endif
954117058Ssam	/*
955117058Ssam	 * CBIMM means unconditionally do the callback immediately;
956117058Ssam	 * CBIFSYNC means do the callback immediately only if the
957117058Ssam	 * operation was done synchronously.  Both are used to avoid
958117058Ssam	 * doing extraneous context switches; the latter is mostly
959117058Ssam	 * used with the software crypto driver.
960117058Ssam	 */
961117058Ssam	if ((crp->crp_flags & CRYPTO_F_CBIMM) ||
962117058Ssam	    ((crp->crp_flags & CRYPTO_F_CBIFSYNC) &&
963117058Ssam	     (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) {
964111297Ssam		/*
965111297Ssam		 * Do the callback directly.  This is ok when the
966111297Ssam		 * callback routine does very little (e.g. the
967111297Ssam		 * /dev/crypto callback method just does a wakeup).
968111297Ssam		 */
969111297Ssam#ifdef CRYPTO_TIMING
970111297Ssam		if (crypto_timing) {
971111297Ssam			/*
972111297Ssam			 * NB: We must copy the timestamp before
973111297Ssam			 * doing the callback as the cryptop is
974111297Ssam			 * likely to be reclaimed.
975111297Ssam			 */
976111297Ssam			struct bintime t = crp->crp_tstamp;
977111297Ssam			crypto_tstat(&cryptostats.cs_cb, &t);
978111297Ssam			crp->crp_callback(crp);
979111297Ssam			crypto_tstat(&cryptostats.cs_finis, &t);
980111297Ssam		} else
981111297Ssam#endif
982111297Ssam			crp->crp_callback(crp);
983111297Ssam	} else {
984111297Ssam		/*
985111297Ssam		 * Normal case; queue the callback for the thread.
986111297Ssam		 */
987111297Ssam		CRYPTO_RETQ_LOCK();
988158826Spjd		if (CRYPTO_RETQ_EMPTY())
989158702Spjd			wakeup_one(&crp_ret_q);	/* shared wait channel */
990111297Ssam		TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next);
991111297Ssam		CRYPTO_RETQ_UNLOCK();
992111297Ssam	}
993104476Ssam}
994104476Ssam
995104476Ssam/*
996104476Ssam * Invoke the callback on behalf of the driver.
997104476Ssam */
998104476Ssamvoid
999104476Ssamcrypto_kdone(struct cryptkop *krp)
1000104476Ssam{
1001158702Spjd	struct cryptocap *cap;
1002104476Ssam
1003108587Ssam	if (krp->krp_status != 0)
1004108587Ssam		cryptostats.cs_kerrs++;
1005158702Spjd	CRYPTO_DRIVER_LOCK();
1006158702Spjd	/* XXX: What if driver is loaded in the meantime? */
1007158702Spjd	if (krp->krp_hid < crypto_drivers_num) {
1008158702Spjd		cap = &crypto_drivers[krp->krp_hid];
1009158702Spjd		cap->cc_koperations--;
1010158702Spjd		KASSERT(cap->cc_koperations >= 0, ("cc_koperations < 0"));
1011158702Spjd		if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
1012158702Spjd			crypto_remove(cap);
1013158702Spjd	}
1014158702Spjd	CRYPTO_DRIVER_UNLOCK();
1015104476Ssam	CRYPTO_RETQ_LOCK();
1016158826Spjd	if (CRYPTO_RETQ_EMPTY())
1017158702Spjd		wakeup_one(&crp_ret_q);		/* shared wait channel */
1018104476Ssam	TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next);
1019104628Ssam	CRYPTO_RETQ_UNLOCK();
1020104476Ssam}
1021104476Ssam
1022104476Ssamint
1023104476Ssamcrypto_getfeat(int *featp)
1024104476Ssam{
1025104476Ssam	int hid, kalg, feat = 0;
1026104476Ssam
1027104476Ssam	if (!crypto_userasymcrypto)
1028104476Ssam		goto out;
1029104476Ssam
1030104476Ssam	CRYPTO_DRIVER_LOCK();
1031104476Ssam	for (hid = 0; hid < crypto_drivers_num; hid++) {
1032104476Ssam		if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) &&
1033104476Ssam		    !crypto_devallowsoft) {
1034104476Ssam			continue;
1035104476Ssam		}
1036104476Ssam		if (crypto_drivers[hid].cc_kprocess == NULL)
1037104476Ssam			continue;
1038104476Ssam		for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++)
1039104476Ssam			if ((crypto_drivers[hid].cc_kalg[kalg] &
1040104476Ssam			    CRYPTO_ALG_FLAG_SUPPORTED) != 0)
1041104476Ssam				feat |=  1 << kalg;
1042104476Ssam	}
1043104476Ssam	CRYPTO_DRIVER_UNLOCK();
1044104476Ssamout:
1045104476Ssam	*featp = feat;
1046104476Ssam	return (0);
1047104476Ssam}
1048104476Ssam
1049108588Ssam/*
1050108588Ssam * Terminate a thread at module unload.  The process that
1051108588Ssam * initiated this is waiting for us to signal that we're gone;
1052108588Ssam * wake it up and exit.  We use the driver table lock to insure
1053108588Ssam * we don't do the wakeup before they're waiting.  There is no
1054108588Ssam * race here because the waiter sleeps on the proc lock for the
1055108588Ssam * thread so it gets notified at the right time because of an
1056108588Ssam * extra wakeup that's done in exit1().
1057108588Ssam */
1058104476Ssamstatic void
1059108588Ssamcrypto_finis(void *chan)
1060104476Ssam{
1061108588Ssam	CRYPTO_DRIVER_LOCK();
1062108588Ssam	wakeup_one(chan);
1063108588Ssam	CRYPTO_DRIVER_UNLOCK();
1064108588Ssam	kthread_exit(0);
1065104476Ssam}
1066104476Ssam
1067104476Ssam/*
1068104628Ssam * Crypto thread, dispatches crypto requests.
1069104476Ssam */
1070104476Ssamstatic void
1071104476Ssamcrypto_proc(void)
1072104476Ssam{
1073104628Ssam	struct cryptop *crp, *submit;
1074104628Ssam	struct cryptkop *krp;
1075104476Ssam	struct cryptocap *cap;
1076158702Spjd	u_int32_t hid;
1077104476Ssam	int result, hint;
1078104476Ssam
1079104628Ssam	CRYPTO_Q_LOCK();
1080104476Ssam	for (;;) {
1081104476Ssam		/*
1082104476Ssam		 * Find the first element in the queue that can be
1083104476Ssam		 * processed and look-ahead to see if multiple ops
1084104476Ssam		 * are ready for the same driver.
1085104476Ssam		 */
1086104476Ssam		submit = NULL;
1087104476Ssam		hint = 0;
1088104476Ssam		TAILQ_FOREACH(crp, &crp_q, crp_next) {
1089158702Spjd			hid = CRYPTO_SESID2HID(crp->crp_sid);
1090104476Ssam			cap = crypto_checkdriver(hid);
1091158702Spjd			/*
1092158702Spjd			 * Driver cannot disappeared when there is an active
1093158702Spjd			 * session.
1094158702Spjd			 */
1095158716Spjd			KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
1096158716Spjd			    __func__, __LINE__));
1097104476Ssam			if (cap == NULL || cap->cc_process == NULL) {
1098104476Ssam				/* Op needs to be migrated, process it. */
1099104476Ssam				if (submit == NULL)
1100104476Ssam					submit = crp;
1101104476Ssam				break;
1102104476Ssam			}
1103104476Ssam			if (!cap->cc_qblocked) {
1104104476Ssam				if (submit != NULL) {
1105104476Ssam					/*
1106104476Ssam					 * We stop on finding another op,
1107104476Ssam					 * regardless whether its for the same
1108104476Ssam					 * driver or not.  We could keep
1109104476Ssam					 * searching the queue but it might be
1110104476Ssam					 * better to just use a per-driver
1111104476Ssam					 * queue instead.
1112104476Ssam					 */
1113116924Ssam					if (CRYPTO_SESID2HID(submit->crp_sid) == hid)
1114104476Ssam						hint = CRYPTO_HINT_MORE;
1115104476Ssam					break;
1116104476Ssam				} else {
1117104476Ssam					submit = crp;
1118111297Ssam					if ((submit->crp_flags & CRYPTO_F_BATCH) == 0)
1119104476Ssam						break;
1120104476Ssam					/* keep scanning for more are q'd */
1121104476Ssam				}
1122104476Ssam			}
1123104476Ssam		}
1124104476Ssam		if (submit != NULL) {
1125104476Ssam			TAILQ_REMOVE(&crp_q, submit, crp_next);
1126158702Spjd			hid = CRYPTO_SESID2HID(submit->crp_sid);
1127158702Spjd			cap = crypto_checkdriver(hid);
1128158716Spjd			KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
1129158716Spjd			    __func__, __LINE__));
1130158702Spjd			result = crypto_invoke(cap, submit, hint);
1131104476Ssam			if (result == ERESTART) {
1132104476Ssam				/*
1133104476Ssam				 * The driver ran out of resources, mark the
1134104476Ssam				 * driver ``blocked'' for cryptop's and put
1135104476Ssam				 * the request back in the queue.  It would
1136104476Ssam				 * best to put the request back where we got
1137104476Ssam				 * it but that's hard so for now we put it
1138104476Ssam				 * at the front.  This should be ok; putting
1139104476Ssam				 * it at the end does not work.
1140104476Ssam				 */
1141104476Ssam				/* XXX validate sid again? */
1142116924Ssam				crypto_drivers[CRYPTO_SESID2HID(submit->crp_sid)].cc_qblocked = 1;
1143104476Ssam				TAILQ_INSERT_HEAD(&crp_q, submit, crp_next);
1144108587Ssam				cryptostats.cs_blocks++;
1145104476Ssam			}
1146104476Ssam		}
1147104476Ssam
1148104476Ssam		/* As above, but for key ops */
1149104476Ssam		TAILQ_FOREACH(krp, &crp_kq, krp_next) {
1150104476Ssam			cap = crypto_checkdriver(krp->krp_hid);
1151104476Ssam			if (cap == NULL || cap->cc_kprocess == NULL) {
1152104476Ssam				/* Op needs to be migrated, process it. */
1153104476Ssam				break;
1154104476Ssam			}
1155104476Ssam			if (!cap->cc_kqblocked)
1156104476Ssam				break;
1157104476Ssam		}
1158104476Ssam		if (krp != NULL) {
1159104476Ssam			TAILQ_REMOVE(&crp_kq, krp, krp_next);
1160158702Spjd			result = crypto_kinvoke(krp);
1161104476Ssam			if (result == ERESTART) {
1162104476Ssam				/*
1163104476Ssam				 * The driver ran out of resources, mark the
1164104476Ssam				 * driver ``blocked'' for cryptkop's and put
1165104476Ssam				 * the request back in the queue.  It would
1166104476Ssam				 * best to put the request back where we got
1167104476Ssam				 * it but that's hard so for now we put it
1168104476Ssam				 * at the front.  This should be ok; putting
1169104476Ssam				 * it at the end does not work.
1170104476Ssam				 */
1171104476Ssam				/* XXX validate sid again? */
1172104476Ssam				crypto_drivers[krp->krp_hid].cc_kqblocked = 1;
1173104476Ssam				TAILQ_INSERT_HEAD(&crp_kq, krp, krp_next);
1174108587Ssam				cryptostats.cs_kblocks++;
1175104476Ssam			}
1176104476Ssam		}
1177104476Ssam
1178104628Ssam		if (submit == NULL && krp == NULL) {
1179104476Ssam			/*
1180104476Ssam			 * Nothing more to be processed.  Sleep until we're
1181104476Ssam			 * woken because there are more ops to process.
1182104476Ssam			 * This happens either by submission or by a driver
1183104476Ssam			 * becoming unblocked and notifying us through
1184104476Ssam			 * crypto_unblock.  Note that when we wakeup we
1185104476Ssam			 * start processing each queue again from the
1186104476Ssam			 * front. It's not clear that it's important to
1187104476Ssam			 * preserve this ordering since ops may finish
1188104476Ssam			 * out of order if dispatched to different devices
1189104476Ssam			 * and some become blocked while others do not.
1190104476Ssam			 */
1191158827Spjd			crp_sleep = 1;
1192104628Ssam			msleep(&crp_q, &crypto_q_mtx, PWAIT, "crypto_wait", 0);
1193158827Spjd			crp_sleep = 0;
1194108588Ssam			if (cryptoproc == NULL)
1195108588Ssam				break;
1196108587Ssam			cryptostats.cs_intrs++;
1197104476Ssam		}
1198104476Ssam	}
1199108588Ssam	CRYPTO_Q_UNLOCK();
1200104628Ssam
1201108588Ssam	crypto_finis(&crp_q);
1202104628Ssam}
1203104628Ssam
1204104628Ssam/*
1205104628Ssam * Crypto returns thread, does callbacks for processed crypto requests.
1206104628Ssam * Callbacks are done here, rather than in the crypto drivers, because
1207104628Ssam * callbacks typically are expensive and would slow interrupt handling.
1208104628Ssam */
1209104628Ssamstatic void
1210104628Ssamcrypto_ret_proc(void)
1211104628Ssam{
1212104628Ssam	struct cryptop *crpt;
1213104628Ssam	struct cryptkop *krpt;
1214104628Ssam
1215104628Ssam	CRYPTO_RETQ_LOCK();
1216104628Ssam	for (;;) {
1217104628Ssam		/* Harvest return q's for completed ops */
1218104628Ssam		crpt = TAILQ_FIRST(&crp_ret_q);
1219104628Ssam		if (crpt != NULL)
1220104628Ssam			TAILQ_REMOVE(&crp_ret_q, crpt, crp_next);
1221104628Ssam
1222104628Ssam		krpt = TAILQ_FIRST(&crp_ret_kq);
1223104628Ssam		if (krpt != NULL)
1224104628Ssam			TAILQ_REMOVE(&crp_ret_kq, krpt, krp_next);
1225104628Ssam
1226104628Ssam		if (crpt != NULL || krpt != NULL) {
1227104628Ssam			CRYPTO_RETQ_UNLOCK();
1228104628Ssam			/*
1229104628Ssam			 * Run callbacks unlocked.
1230104628Ssam			 */
1231108587Ssam			if (crpt != NULL) {
1232108587Ssam#ifdef CRYPTO_TIMING
1233108587Ssam				if (crypto_timing) {
1234108587Ssam					/*
1235108587Ssam					 * NB: We must copy the timestamp before
1236108587Ssam					 * doing the callback as the cryptop is
1237108587Ssam					 * likely to be reclaimed.
1238108587Ssam					 */
1239108587Ssam					struct bintime t = crpt->crp_tstamp;
1240108587Ssam					crypto_tstat(&cryptostats.cs_cb, &t);
1241108587Ssam					crpt->crp_callback(crpt);
1242108587Ssam					crypto_tstat(&cryptostats.cs_finis, &t);
1243108587Ssam				} else
1244108587Ssam#endif
1245108587Ssam					crpt->crp_callback(crpt);
1246108587Ssam			}
1247104628Ssam			if (krpt != NULL)
1248104628Ssam				krpt->krp_callback(krpt);
1249104628Ssam			CRYPTO_RETQ_LOCK();
1250104628Ssam		} else {
1251104628Ssam			/*
1252104628Ssam			 * Nothing more to be processed.  Sleep until we're
1253104628Ssam			 * woken because there are more returns to process.
1254104628Ssam			 */
1255104628Ssam			msleep(&crp_ret_q, &crypto_ret_q_mtx, PWAIT,
1256104628Ssam				"crypto_ret_wait", 0);
1257108588Ssam			if (cryptoretproc == NULL)
1258108588Ssam				break;
1259108587Ssam			cryptostats.cs_rets++;
1260104628Ssam		}
1261104628Ssam	}
1262108588Ssam	CRYPTO_RETQ_UNLOCK();
1263108588Ssam
1264108588Ssam	crypto_finis(&crp_ret_q);
1265104628Ssam}
1266