crypto.c revision 158826
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 158826 2006-05-22 09:58:34Z 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 */
62104476Ssamstatic	TAILQ_HEAD(,cryptop) crp_q;		/* request queues */
63104476Ssamstatic	TAILQ_HEAD(,cryptkop) crp_kq;
64104476Ssamstatic	struct mtx crypto_q_mtx;
65104476Ssam#define	CRYPTO_Q_LOCK()		mtx_lock(&crypto_q_mtx)
66104476Ssam#define	CRYPTO_Q_UNLOCK()	mtx_unlock(&crypto_q_mtx)
67158702Spjd#define	CRYPTO_Q_EMPTY()	(TAILQ_EMPTY(&crp_q) && TAILQ_EMPTY(&crp_kq))
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{
265104476Ssam	struct cryptoini *cr;
266104476Ssam	u_int32_t hid, lid;
267104476Ssam	int err = EINVAL;
268104476Ssam
269104476Ssam	CRYPTO_DRIVER_LOCK();
270104476Ssam
271104476Ssam	if (crypto_drivers == NULL)
272104476Ssam		goto done;
273104476Ssam
274104476Ssam	/*
275104476Ssam	 * The algorithm we use here is pretty stupid; just use the
276104476Ssam	 * first driver that supports all the algorithms we need.
277104476Ssam	 *
278104476Ssam	 * XXX We need more smarts here (in real life too, but that's
279104476Ssam	 * XXX another story altogether).
280104476Ssam	 */
281104476Ssam
282104476Ssam	for (hid = 0; hid < crypto_drivers_num; hid++) {
283116924Ssam		struct cryptocap *cap = &crypto_drivers[hid];
284104476Ssam		/*
285104476Ssam		 * If it's not initialized or has remaining sessions
286104476Ssam		 * referencing it, skip.
287104476Ssam		 */
288116924Ssam		if (cap->cc_newsession == NULL ||
289116924Ssam		    (cap->cc_flags & CRYPTOCAP_F_CLEANUP))
290104476Ssam			continue;
291104476Ssam
292104476Ssam		/* Hardware required -- ignore software drivers. */
293116924Ssam		if (hard > 0 && (cap->cc_flags & CRYPTOCAP_F_SOFTWARE))
294104476Ssam			continue;
295104476Ssam		/* Software required -- ignore hardware drivers. */
296116924Ssam		if (hard < 0 && (cap->cc_flags & CRYPTOCAP_F_SOFTWARE) == 0)
297104476Ssam			continue;
298104476Ssam
299104476Ssam		/* See if all the algorithms are supported. */
300104476Ssam		for (cr = cri; cr; cr = cr->cri_next)
301116924Ssam			if (cap->cc_alg[cr->cri_alg] == 0)
302104476Ssam				break;
303104476Ssam
304104476Ssam		if (cr == NULL) {
305104476Ssam			/* Ok, all algorithms are supported. */
306104476Ssam
307104476Ssam			/*
308104476Ssam			 * Can't do everything in one session.
309104476Ssam			 *
310104476Ssam			 * XXX Fix this. We need to inject a "virtual" session layer right
311104476Ssam			 * XXX about here.
312104476Ssam			 */
313104476Ssam
314104476Ssam			/* Call the driver initialization routine. */
315104476Ssam			lid = hid;		/* Pass the driver ID. */
316116924Ssam			err = (*cap->cc_newsession)(cap->cc_arg, &lid, cri);
317104476Ssam			if (err == 0) {
318116924Ssam				/* XXX assert (hid &~ 0xffffff) == 0 */
319116924Ssam				/* XXX assert (cap->cc_flags &~ 0xff) == 0 */
320116924Ssam				(*sid) = ((cap->cc_flags & 0xff) << 24) | hid;
321104476Ssam				(*sid) <<= 32;
322104476Ssam				(*sid) |= (lid & 0xffffffff);
323116924Ssam				cap->cc_sessions++;
324104476Ssam			}
325104476Ssam			break;
326104476Ssam		}
327104476Ssam	}
328104476Ssamdone:
329104476Ssam	CRYPTO_DRIVER_UNLOCK();
330104476Ssam	return err;
331104476Ssam}
332104476Ssam
333158702Spjdstatic void
334158702Spjdcrypto_remove(struct cryptocap *cap)
335158702Spjd{
336158702Spjd
337158702Spjd	mtx_assert(&crypto_drivers_mtx, MA_OWNED);
338158702Spjd	if (cap->cc_sessions == 0 && cap->cc_koperations == 0)
339158702Spjd		bzero(cap, sizeof(*cap));
340158702Spjd}
341158702Spjd
342104476Ssam/*
343104476Ssam * Delete an existing session (or a reserved session on an unregistered
344104476Ssam * driver).
345104476Ssam */
346104476Ssamint
347104476Ssamcrypto_freesession(u_int64_t sid)
348104476Ssam{
349158702Spjd	struct cryptocap *cap;
350104476Ssam	u_int32_t hid;
351104476Ssam	int err;
352104476Ssam
353104476Ssam	CRYPTO_DRIVER_LOCK();
354104476Ssam
355104476Ssam	if (crypto_drivers == NULL) {
356104476Ssam		err = EINVAL;
357104476Ssam		goto done;
358104476Ssam	}
359104476Ssam
360104476Ssam	/* Determine two IDs. */
361116924Ssam	hid = CRYPTO_SESID2HID(sid);
362104476Ssam
363104476Ssam	if (hid >= crypto_drivers_num) {
364104476Ssam		err = ENOENT;
365104476Ssam		goto done;
366104476Ssam	}
367158702Spjd	cap = &crypto_drivers[hid];
368104476Ssam
369158702Spjd	if (cap->cc_sessions)
370158702Spjd		cap->cc_sessions--;
371104476Ssam
372104476Ssam	/* Call the driver cleanup routine, if available. */
373158702Spjd	if (cap->cc_freesession)
374158702Spjd		err = cap->cc_freesession(cap->cc_arg, sid);
375104476Ssam	else
376104476Ssam		err = 0;
377104476Ssam
378158702Spjd	if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
379158702Spjd		crypto_remove(cap);
380104476Ssam
381104476Ssamdone:
382104476Ssam	CRYPTO_DRIVER_UNLOCK();
383104476Ssam	return err;
384104476Ssam}
385104476Ssam
386104476Ssam/*
387104476Ssam * Return an unused driver id.  Used by drivers prior to registering
388104476Ssam * support for the algorithms they handle.
389104476Ssam */
390104476Ssamint32_t
391104476Ssamcrypto_get_driverid(u_int32_t flags)
392104476Ssam{
393104476Ssam	struct cryptocap *newdrv;
394104476Ssam	int i;
395104476Ssam
396104476Ssam	CRYPTO_DRIVER_LOCK();
397104476Ssam
398158702Spjd	for (i = 0; i < crypto_drivers_num; i++) {
399104476Ssam		if (crypto_drivers[i].cc_process == NULL &&
400158702Spjd		    (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0) {
401104476Ssam			break;
402158702Spjd		}
403158702Spjd	}
404104476Ssam
405104476Ssam	/* Out of entries, allocate some more. */
406104476Ssam	if (i == crypto_drivers_num) {
407104476Ssam		/* Be careful about wrap-around. */
408104476Ssam		if (2 * crypto_drivers_num <= crypto_drivers_num) {
409104476Ssam			CRYPTO_DRIVER_UNLOCK();
410104476Ssam			printf("crypto: driver count wraparound!\n");
411104476Ssam			return -1;
412104476Ssam		}
413104476Ssam
414104476Ssam		newdrv = malloc(2 * crypto_drivers_num *
415104476Ssam		    sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
416104476Ssam		if (newdrv == NULL) {
417104476Ssam			CRYPTO_DRIVER_UNLOCK();
418104476Ssam			printf("crypto: no space to expand driver table!\n");
419104476Ssam			return -1;
420104476Ssam		}
421104476Ssam
422104476Ssam		bcopy(crypto_drivers, newdrv,
423104476Ssam		    crypto_drivers_num * sizeof(struct cryptocap));
424104476Ssam
425104476Ssam		crypto_drivers_num *= 2;
426104476Ssam
427104476Ssam		free(crypto_drivers, M_CRYPTO_DATA);
428104476Ssam		crypto_drivers = newdrv;
429104476Ssam	}
430104476Ssam
431104476Ssam	/* NB: state is zero'd on free */
432104476Ssam	crypto_drivers[i].cc_sessions = 1;	/* Mark */
433104476Ssam	crypto_drivers[i].cc_flags = flags;
434104476Ssam	if (bootverbose)
435104476Ssam		printf("crypto: assign driver %u, flags %u\n", i, flags);
436104476Ssam
437104476Ssam	CRYPTO_DRIVER_UNLOCK();
438104476Ssam
439104476Ssam	return i;
440104476Ssam}
441104476Ssam
442104476Ssamstatic struct cryptocap *
443104476Ssamcrypto_checkdriver(u_int32_t hid)
444104476Ssam{
445104476Ssam	if (crypto_drivers == NULL)
446104476Ssam		return NULL;
447104476Ssam	return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]);
448104476Ssam}
449104476Ssam
450104476Ssam/*
451104476Ssam * Register support for a key-related algorithm.  This routine
452104476Ssam * is called once for each algorithm supported a driver.
453104476Ssam */
454104476Ssamint
455104476Ssamcrypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags,
456104476Ssam    int (*kprocess)(void*, struct cryptkop *, int),
457104476Ssam    void *karg)
458104476Ssam{
459104476Ssam	struct cryptocap *cap;
460104476Ssam	int err;
461104476Ssam
462104476Ssam	CRYPTO_DRIVER_LOCK();
463104476Ssam
464104476Ssam	cap = crypto_checkdriver(driverid);
465104476Ssam	if (cap != NULL &&
466104476Ssam	    (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) {
467104476Ssam		/*
468104476Ssam		 * XXX Do some performance testing to determine placing.
469104476Ssam		 * XXX We probably need an auxiliary data structure that
470104476Ssam		 * XXX describes relative performances.
471104476Ssam		 */
472104476Ssam
473104476Ssam		cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
474104476Ssam		if (bootverbose)
475104476Ssam			printf("crypto: driver %u registers key alg %u flags %u\n"
476104476Ssam				, driverid
477104476Ssam				, kalg
478104476Ssam				, flags
479104476Ssam			);
480104476Ssam
481104476Ssam		if (cap->cc_kprocess == NULL) {
482104476Ssam			cap->cc_karg = karg;
483104476Ssam			cap->cc_kprocess = kprocess;
484104476Ssam		}
485104476Ssam		err = 0;
486104476Ssam	} else
487104476Ssam		err = EINVAL;
488104476Ssam
489104476Ssam	CRYPTO_DRIVER_UNLOCK();
490104476Ssam	return err;
491104476Ssam}
492104476Ssam
493104476Ssam/*
494104476Ssam * Register support for a non-key-related algorithm.  This routine
495104476Ssam * is called once for each such algorithm supported by a driver.
496104476Ssam */
497104476Ssamint
498104476Ssamcrypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
499104476Ssam    u_int32_t flags,
500104476Ssam    int (*newses)(void*, u_int32_t*, struct cryptoini*),
501104476Ssam    int (*freeses)(void*, u_int64_t),
502104476Ssam    int (*process)(void*, struct cryptop *, int),
503104476Ssam    void *arg)
504104476Ssam{
505104476Ssam	struct cryptocap *cap;
506104476Ssam	int err;
507104476Ssam
508104476Ssam	CRYPTO_DRIVER_LOCK();
509104476Ssam
510104476Ssam	cap = crypto_checkdriver(driverid);
511104476Ssam	/* NB: algorithms are in the range [1..max] */
512104476Ssam	if (cap != NULL &&
513104476Ssam	    (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) {
514104476Ssam		/*
515104476Ssam		 * XXX Do some performance testing to determine placing.
516104476Ssam		 * XXX We probably need an auxiliary data structure that
517104476Ssam		 * XXX describes relative performances.
518104476Ssam		 */
519104476Ssam
520104476Ssam		cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
521104476Ssam		cap->cc_max_op_len[alg] = maxoplen;
522104476Ssam		if (bootverbose)
523104476Ssam			printf("crypto: driver %u registers alg %u flags %u maxoplen %u\n"
524104476Ssam				, driverid
525104476Ssam				, alg
526104476Ssam				, flags
527104476Ssam				, maxoplen
528104476Ssam			);
529104476Ssam
530104476Ssam		if (cap->cc_process == NULL) {
531104476Ssam			cap->cc_arg = arg;
532104476Ssam			cap->cc_newsession = newses;
533104476Ssam			cap->cc_process = process;
534104476Ssam			cap->cc_freesession = freeses;
535104476Ssam			cap->cc_sessions = 0;		/* Unmark */
536104476Ssam		}
537104476Ssam		err = 0;
538104476Ssam	} else
539104476Ssam		err = EINVAL;
540104476Ssam
541104476Ssam	CRYPTO_DRIVER_UNLOCK();
542104476Ssam	return err;
543104476Ssam}
544104476Ssam
545104476Ssam/*
546104476Ssam * Unregister a crypto driver. If there are pending sessions using it,
547104476Ssam * leave enough information around so that subsequent calls using those
548104476Ssam * sessions will correctly detect the driver has been unregistered and
549104476Ssam * reroute requests.
550104476Ssam */
551104476Ssamint
552104476Ssamcrypto_unregister(u_int32_t driverid, int alg)
553104476Ssam{
554158702Spjd	struct cryptocap *cap;
555158702Spjd	u_int32_t ses, kops;
556104476Ssam	int i, err;
557104476Ssam
558104476Ssam	CRYPTO_DRIVER_LOCK();
559104476Ssam
560104476Ssam	cap = crypto_checkdriver(driverid);
561104476Ssam	if (cap != NULL &&
562104476Ssam	    (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) &&
563104476Ssam	    cap->cc_alg[alg] != 0) {
564104476Ssam		cap->cc_alg[alg] = 0;
565104476Ssam		cap->cc_max_op_len[alg] = 0;
566104476Ssam
567104476Ssam		/* Was this the last algorithm ? */
568104476Ssam		for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
569104476Ssam			if (cap->cc_alg[i] != 0)
570104476Ssam				break;
571104476Ssam
572104476Ssam		if (i == CRYPTO_ALGORITHM_MAX + 1) {
573104476Ssam			ses = cap->cc_sessions;
574158702Spjd			kops = cap->cc_koperations;
575158702Spjd			bzero(cap, sizeof(*cap));
576158702Spjd			if (ses != 0 || kops != 0) {
577104476Ssam				/*
578104476Ssam				 * If there are pending sessions, just mark as invalid.
579104476Ssam				 */
580104476Ssam				cap->cc_flags |= CRYPTOCAP_F_CLEANUP;
581104476Ssam				cap->cc_sessions = ses;
582158702Spjd				cap->cc_koperations = kops;
583104476Ssam			}
584104476Ssam		}
585104476Ssam		err = 0;
586104476Ssam	} else
587104476Ssam		err = EINVAL;
588104476Ssam
589104476Ssam	CRYPTO_DRIVER_UNLOCK();
590104476Ssam	return err;
591104476Ssam}
592104476Ssam
593104476Ssam/*
594104476Ssam * Unregister all algorithms associated with a crypto driver.
595104476Ssam * If there are pending sessions using it, leave enough information
596104476Ssam * around so that subsequent calls using those sessions will
597104476Ssam * correctly detect the driver has been unregistered and reroute
598104476Ssam * requests.
599104476Ssam */
600104476Ssamint
601104476Ssamcrypto_unregister_all(u_int32_t driverid)
602104476Ssam{
603158702Spjd	struct cryptocap *cap;
604158702Spjd	u_int32_t ses, kops;
605104476Ssam	int i, err;
606104476Ssam
607104476Ssam	CRYPTO_DRIVER_LOCK();
608104476Ssam
609104476Ssam	cap = crypto_checkdriver(driverid);
610104476Ssam	if (cap != NULL) {
611104476Ssam		for (i = CRYPTO_ALGORITHM_MIN; i <= CRYPTO_ALGORITHM_MAX; i++) {
612104476Ssam			cap->cc_alg[i] = 0;
613104476Ssam			cap->cc_max_op_len[i] = 0;
614104476Ssam		}
615104476Ssam		ses = cap->cc_sessions;
616158702Spjd		kops = cap->cc_koperations;
617158702Spjd		bzero(cap, sizeof(*cap));
618158702Spjd		if (ses != 0 || kops != 0) {
619104476Ssam			/*
620104476Ssam			 * If there are pending sessions, just mark as invalid.
621104476Ssam			 */
622104476Ssam			cap->cc_flags |= CRYPTOCAP_F_CLEANUP;
623104476Ssam			cap->cc_sessions = ses;
624158702Spjd			cap->cc_koperations = kops;
625104476Ssam		}
626104476Ssam		err = 0;
627104476Ssam	} else
628104476Ssam		err = EINVAL;
629104476Ssam
630104476Ssam	CRYPTO_DRIVER_UNLOCK();
631104476Ssam	return err;
632104476Ssam}
633104476Ssam
634104476Ssam/*
635104476Ssam * Clear blockage on a driver.  The what parameter indicates whether
636104476Ssam * the driver is now ready for cryptop's and/or cryptokop's.
637104476Ssam */
638104476Ssamint
639104476Ssamcrypto_unblock(u_int32_t driverid, int what)
640104476Ssam{
641104476Ssam	struct cryptocap *cap;
642104476Ssam	int needwakeup, err;
643104476Ssam
644104476Ssam	CRYPTO_Q_LOCK();
645104476Ssam	cap = crypto_checkdriver(driverid);
646104476Ssam	if (cap != NULL) {
647104628Ssam		needwakeup = 0;
648104476Ssam		if (what & CRYPTO_SYMQ) {
649104476Ssam			needwakeup |= cap->cc_qblocked;
650104476Ssam			cap->cc_qblocked = 0;
651104476Ssam		}
652104476Ssam		if (what & CRYPTO_ASYMQ) {
653104476Ssam			needwakeup |= cap->cc_kqblocked;
654104476Ssam			cap->cc_kqblocked = 0;
655104476Ssam		}
656104628Ssam		if (needwakeup)
657104628Ssam			wakeup_one(&crp_q);
658104476Ssam		err = 0;
659104476Ssam	} else
660104476Ssam		err = EINVAL;
661104476Ssam	CRYPTO_Q_UNLOCK();
662104476Ssam
663104476Ssam	return err;
664104476Ssam}
665104476Ssam
666104476Ssam/*
667104476Ssam * Add a crypto request to a queue, to be processed by the kernel thread.
668104476Ssam */
669104476Ssamint
670104476Ssamcrypto_dispatch(struct cryptop *crp)
671104476Ssam{
672158702Spjd	struct cryptocap *cap;
673158702Spjd	u_int32_t hid;
674158702Spjd	int result;
675104476Ssam
676108587Ssam	cryptostats.cs_ops++;
677108587Ssam
678108587Ssam#ifdef CRYPTO_TIMING
679108587Ssam	if (crypto_timing)
680108587Ssam		binuptime(&crp->crp_tstamp);
681108587Ssam#endif
682108587Ssam
683158702Spjd	hid = CRYPTO_SESID2HID(crp->crp_sid);
684158702Spjd
685111297Ssam	if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) {
686111297Ssam		/*
687111297Ssam		 * Caller marked the request to be processed
688111297Ssam		 * immediately; dispatch it directly to the
689111297Ssam		 * driver unless the driver is currently blocked.
690111297Ssam		 */
691111297Ssam		cap = crypto_checkdriver(hid);
692158702Spjd		/* Driver cannot disappeared when there is an active session. */
693158702Spjd		KASSERT(cap != NULL, ("%s: Driver disappeared.", __func__));
694158702Spjd		if (!cap->cc_qblocked) {
695158702Spjd			result = crypto_invoke(cap, crp, 0);
696158702Spjd			if (result != ERESTART)
697158702Spjd				return (result);
698158823Spjd			/*
699158823Spjd			 * The driver ran out of resources, put the request on
700158823Spjd			 * the queue.
701158823Spjd			 */
702108990Ssam		}
703108990Ssam	}
704158702Spjd	CRYPTO_Q_LOCK();
705158702Spjd	if (CRYPTO_Q_EMPTY())
706157665Spjd		wakeup_one(&crp_q);
707158702Spjd	TAILQ_INSERT_TAIL(&crp_q, crp, crp_next);
708115746Ssam	CRYPTO_Q_UNLOCK();
709158702Spjd	return 0;
710104476Ssam}
711104476Ssam
712104476Ssam/*
713104476Ssam * Add an asymetric crypto request to a queue,
714104476Ssam * to be processed by the kernel thread.
715104476Ssam */
716104476Ssamint
717104476Ssamcrypto_kdispatch(struct cryptkop *krp)
718104476Ssam{
719158702Spjd	int result;
720104476Ssam
721108587Ssam	cryptostats.cs_kops++;
722108587Ssam
723158702Spjd	result = crypto_kinvoke(krp);
724158702Spjd	if (result != ERESTART)
725158702Spjd		return (result);
726104476Ssam	CRYPTO_Q_LOCK();
727158702Spjd	if (CRYPTO_Q_EMPTY())
728157665Spjd		wakeup_one(&crp_q);
729158702Spjd	TAILQ_INSERT_TAIL(&crp_kq, krp, krp_next);
730104476Ssam	CRYPTO_Q_UNLOCK();
731104476Ssam
732158702Spjd	return 0;
733104476Ssam}
734104476Ssam
735104476Ssam/*
736104476Ssam * Dispatch an assymetric crypto request to the appropriate crypto devices.
737104476Ssam */
738104476Ssamstatic int
739158702Spjdcrypto_kinvoke(struct cryptkop *krp)
740104476Ssam{
741158702Spjd	struct cryptocap *cap = NULL;
742104476Ssam	u_int32_t hid;
743158702Spjd	int error = 0;
744104476Ssam
745158702Spjd	KASSERT(krp != NULL, ("%s: krp == NULL", __func__));
746158702Spjd	KASSERT(krp->krp_callback != NULL,
747158702Spjd	    ("%s: krp->crp_callback == NULL", __func__));
748104476Ssam
749158702Spjd	CRYPTO_DRIVER_LOCK();
750104476Ssam	for (hid = 0; hid < crypto_drivers_num; hid++) {
751158702Spjd		cap = &crypto_drivers[hid];
752158702Spjd		if (cap == NULL)
753104476Ssam			continue;
754158702Spjd		if ((cap->cc_flags & CRYPTOCAP_F_SOFTWARE) &&
755158702Spjd		    !crypto_devallowsoft) {
756104476Ssam			continue;
757158702Spjd		}
758158702Spjd		if (cap->cc_kprocess == NULL)
759104476Ssam			continue;
760158702Spjd		if (!(cap->cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED))
761158702Spjd			continue;
762158702Spjd		if (cap->cc_kqblocked) {
763158702Spjd			error = ERESTART;
764158702Spjd			continue;
765158702Spjd		}
766158702Spjd		error = 0;
767104476Ssam		break;
768104476Ssam	}
769158702Spjd	krp->krp_hid = hid;
770104476Ssam	if (hid < crypto_drivers_num) {
771158702Spjd		cap->cc_koperations++;
772158702Spjd		CRYPTO_DRIVER_UNLOCK();
773158702Spjd		error = cap->cc_kprocess(cap->cc_karg, krp, 0);
774158702Spjd		CRYPTO_DRIVER_LOCK();
775158702Spjd		if (error == ERESTART) {
776158702Spjd			cap->cc_koperations--;
777158702Spjd			CRYPTO_DRIVER_UNLOCK();
778158702Spjd			return (error);
779158702Spjd		}
780158702Spjd	} else {
781104476Ssam		error = ENODEV;
782158702Spjd	}
783158702Spjd	CRYPTO_DRIVER_UNLOCK();
784104476Ssam
785104476Ssam	if (error) {
786104476Ssam		krp->krp_status = error;
787104628Ssam		crypto_kdone(krp);
788104476Ssam	}
789104476Ssam	return 0;
790104476Ssam}
791104476Ssam
792108587Ssam#ifdef CRYPTO_TIMING
793108587Ssamstatic void
794108587Ssamcrypto_tstat(struct cryptotstat *ts, struct bintime *bt)
795108587Ssam{
796108587Ssam	struct bintime now, delta;
797108587Ssam	struct timespec t;
798108587Ssam	uint64_t u;
799108587Ssam
800108587Ssam	binuptime(&now);
801108587Ssam	u = now.frac;
802108587Ssam	delta.frac = now.frac - bt->frac;
803108587Ssam	delta.sec = now.sec - bt->sec;
804108587Ssam	if (u < delta.frac)
805108587Ssam		delta.sec--;
806108587Ssam	bintime2timespec(&delta, &t);
807108587Ssam	timespecadd(&ts->acc, &t);
808108587Ssam	if (timespeccmp(&t, &ts->min, <))
809108587Ssam		ts->min = t;
810108587Ssam	if (timespeccmp(&t, &ts->max, >))
811108587Ssam		ts->max = t;
812108587Ssam	ts->count++;
813108587Ssam
814108587Ssam	*bt = now;
815108587Ssam}
816108587Ssam#endif
817108587Ssam
818104476Ssam/*
819104476Ssam * Dispatch a crypto request to the appropriate crypto devices.
820104476Ssam */
821104476Ssamstatic int
822158702Spjdcrypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint)
823104476Ssam{
824104476Ssam
825158702Spjd	KASSERT(crp != NULL, ("%s: crp == NULL", __func__));
826158702Spjd	KASSERT(crp->crp_callback != NULL,
827158702Spjd	    ("%s: crp->crp_callback == NULL", __func__));
828158702Spjd	KASSERT(crp->crp_desc != NULL, ("%s: crp->crp_desc == NULL", __func__));
829158702Spjd
830108587Ssam#ifdef CRYPTO_TIMING
831108587Ssam	if (crypto_timing)
832108587Ssam		crypto_tstat(&cryptostats.cs_invoke, &crp->crp_tstamp);
833108587Ssam#endif
834158702Spjd	if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) {
835104476Ssam		struct cryptodesc *crd;
836104476Ssam		u_int64_t nid;
837104476Ssam
838104476Ssam		/*
839104476Ssam		 * Driver has unregistered; migrate the session and return
840104476Ssam		 * an error to the caller so they'll resubmit the op.
841158702Spjd		 *
842158702Spjd		 * XXX: What if there are more already queued requests for this
843158702Spjd		 *      session?
844104476Ssam		 */
845158702Spjd		crypto_freesession(crp->crp_sid);
846158702Spjd
847104476Ssam		for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
848104476Ssam			crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
849104476Ssam
850104476Ssam		if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0)
851104476Ssam			crp->crp_sid = nid;
852104476Ssam
853104476Ssam		crp->crp_etype = EAGAIN;
854104628Ssam		crypto_done(crp);
855104476Ssam		return 0;
856104476Ssam	} else {
857104476Ssam		/*
858104476Ssam		 * Invoke the driver to process the request.
859104476Ssam		 */
860158702Spjd		return cap->cc_process(cap->cc_arg, crp, hint);
861104476Ssam	}
862104476Ssam}
863104476Ssam
864104476Ssam/*
865104476Ssam * Release a set of crypto descriptors.
866104476Ssam */
867104476Ssamvoid
868104476Ssamcrypto_freereq(struct cryptop *crp)
869104476Ssam{
870104476Ssam	struct cryptodesc *crd;
871104476Ssam
872104476Ssam	if (crp == NULL)
873104476Ssam		return;
874104476Ssam
875104476Ssam	while ((crd = crp->crp_desc) != NULL) {
876104476Ssam		crp->crp_desc = crd->crd_next;
877104476Ssam		uma_zfree(cryptodesc_zone, crd);
878104476Ssam	}
879104476Ssam
880104476Ssam	uma_zfree(cryptop_zone, crp);
881104476Ssam}
882104476Ssam
883104476Ssam/*
884104476Ssam * Acquire a set of crypto descriptors.
885104476Ssam */
886104476Ssamstruct cryptop *
887104476Ssamcrypto_getreq(int num)
888104476Ssam{
889104476Ssam	struct cryptodesc *crd;
890104476Ssam	struct cryptop *crp;
891104476Ssam
892108813Ssam	crp = uma_zalloc(cryptop_zone, M_NOWAIT|M_ZERO);
893104476Ssam	if (crp != NULL) {
894104476Ssam		while (num--) {
895108813Ssam			crd = uma_zalloc(cryptodesc_zone, M_NOWAIT|M_ZERO);
896104476Ssam			if (crd == NULL) {
897104476Ssam				crypto_freereq(crp);
898104476Ssam				return NULL;
899104476Ssam			}
900104476Ssam
901104476Ssam			crd->crd_next = crp->crp_desc;
902104476Ssam			crp->crp_desc = crd;
903104476Ssam		}
904104476Ssam	}
905104476Ssam	return crp;
906104476Ssam}
907104476Ssam
908104476Ssam/*
909104476Ssam * Invoke the callback on behalf of the driver.
910104476Ssam */
911104476Ssamvoid
912104476Ssamcrypto_done(struct cryptop *crp)
913104476Ssam{
914115746Ssam	KASSERT((crp->crp_flags & CRYPTO_F_DONE) == 0,
915115746Ssam		("crypto_done: op already done, flags 0x%x", crp->crp_flags));
916115746Ssam	crp->crp_flags |= CRYPTO_F_DONE;
917108587Ssam	if (crp->crp_etype != 0)
918108587Ssam		cryptostats.cs_errs++;
919108587Ssam#ifdef CRYPTO_TIMING
920108587Ssam	if (crypto_timing)
921108587Ssam		crypto_tstat(&cryptostats.cs_done, &crp->crp_tstamp);
922108587Ssam#endif
923117058Ssam	/*
924117058Ssam	 * CBIMM means unconditionally do the callback immediately;
925117058Ssam	 * CBIFSYNC means do the callback immediately only if the
926117058Ssam	 * operation was done synchronously.  Both are used to avoid
927117058Ssam	 * doing extraneous context switches; the latter is mostly
928117058Ssam	 * used with the software crypto driver.
929117058Ssam	 */
930117058Ssam	if ((crp->crp_flags & CRYPTO_F_CBIMM) ||
931117058Ssam	    ((crp->crp_flags & CRYPTO_F_CBIFSYNC) &&
932117058Ssam	     (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) {
933111297Ssam		/*
934111297Ssam		 * Do the callback directly.  This is ok when the
935111297Ssam		 * callback routine does very little (e.g. the
936111297Ssam		 * /dev/crypto callback method just does a wakeup).
937111297Ssam		 */
938111297Ssam#ifdef CRYPTO_TIMING
939111297Ssam		if (crypto_timing) {
940111297Ssam			/*
941111297Ssam			 * NB: We must copy the timestamp before
942111297Ssam			 * doing the callback as the cryptop is
943111297Ssam			 * likely to be reclaimed.
944111297Ssam			 */
945111297Ssam			struct bintime t = crp->crp_tstamp;
946111297Ssam			crypto_tstat(&cryptostats.cs_cb, &t);
947111297Ssam			crp->crp_callback(crp);
948111297Ssam			crypto_tstat(&cryptostats.cs_finis, &t);
949111297Ssam		} else
950111297Ssam#endif
951111297Ssam			crp->crp_callback(crp);
952111297Ssam	} else {
953111297Ssam		/*
954111297Ssam		 * Normal case; queue the callback for the thread.
955111297Ssam		 */
956111297Ssam		CRYPTO_RETQ_LOCK();
957158826Spjd		if (CRYPTO_RETQ_EMPTY())
958158702Spjd			wakeup_one(&crp_ret_q);	/* shared wait channel */
959111297Ssam		TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next);
960111297Ssam		CRYPTO_RETQ_UNLOCK();
961111297Ssam	}
962104476Ssam}
963104476Ssam
964104476Ssam/*
965104476Ssam * Invoke the callback on behalf of the driver.
966104476Ssam */
967104476Ssamvoid
968104476Ssamcrypto_kdone(struct cryptkop *krp)
969104476Ssam{
970158702Spjd	struct cryptocap *cap;
971104476Ssam
972108587Ssam	if (krp->krp_status != 0)
973108587Ssam		cryptostats.cs_kerrs++;
974158702Spjd	CRYPTO_DRIVER_LOCK();
975158702Spjd	/* XXX: What if driver is loaded in the meantime? */
976158702Spjd	if (krp->krp_hid < crypto_drivers_num) {
977158702Spjd		cap = &crypto_drivers[krp->krp_hid];
978158702Spjd		cap->cc_koperations--;
979158702Spjd		KASSERT(cap->cc_koperations >= 0, ("cc_koperations < 0"));
980158702Spjd		if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
981158702Spjd			crypto_remove(cap);
982158702Spjd	}
983158702Spjd	CRYPTO_DRIVER_UNLOCK();
984104476Ssam	CRYPTO_RETQ_LOCK();
985158826Spjd	if (CRYPTO_RETQ_EMPTY())
986158702Spjd		wakeup_one(&crp_ret_q);		/* shared wait channel */
987104476Ssam	TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next);
988104628Ssam	CRYPTO_RETQ_UNLOCK();
989104476Ssam}
990104476Ssam
991104476Ssamint
992104476Ssamcrypto_getfeat(int *featp)
993104476Ssam{
994104476Ssam	int hid, kalg, feat = 0;
995104476Ssam
996104476Ssam	if (!crypto_userasymcrypto)
997104476Ssam		goto out;
998104476Ssam
999104476Ssam	CRYPTO_DRIVER_LOCK();
1000104476Ssam	for (hid = 0; hid < crypto_drivers_num; hid++) {
1001104476Ssam		if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) &&
1002104476Ssam		    !crypto_devallowsoft) {
1003104476Ssam			continue;
1004104476Ssam		}
1005104476Ssam		if (crypto_drivers[hid].cc_kprocess == NULL)
1006104476Ssam			continue;
1007104476Ssam		for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++)
1008104476Ssam			if ((crypto_drivers[hid].cc_kalg[kalg] &
1009104476Ssam			    CRYPTO_ALG_FLAG_SUPPORTED) != 0)
1010104476Ssam				feat |=  1 << kalg;
1011104476Ssam	}
1012104476Ssam	CRYPTO_DRIVER_UNLOCK();
1013104476Ssamout:
1014104476Ssam	*featp = feat;
1015104476Ssam	return (0);
1016104476Ssam}
1017104476Ssam
1018108588Ssam/*
1019108588Ssam * Terminate a thread at module unload.  The process that
1020108588Ssam * initiated this is waiting for us to signal that we're gone;
1021108588Ssam * wake it up and exit.  We use the driver table lock to insure
1022108588Ssam * we don't do the wakeup before they're waiting.  There is no
1023108588Ssam * race here because the waiter sleeps on the proc lock for the
1024108588Ssam * thread so it gets notified at the right time because of an
1025108588Ssam * extra wakeup that's done in exit1().
1026108588Ssam */
1027104476Ssamstatic void
1028108588Ssamcrypto_finis(void *chan)
1029104476Ssam{
1030108588Ssam	CRYPTO_DRIVER_LOCK();
1031108588Ssam	wakeup_one(chan);
1032108588Ssam	CRYPTO_DRIVER_UNLOCK();
1033108588Ssam	kthread_exit(0);
1034104476Ssam}
1035104476Ssam
1036104476Ssam/*
1037104628Ssam * Crypto thread, dispatches crypto requests.
1038104476Ssam */
1039104476Ssamstatic void
1040104476Ssamcrypto_proc(void)
1041104476Ssam{
1042104628Ssam	struct cryptop *crp, *submit;
1043104628Ssam	struct cryptkop *krp;
1044104476Ssam	struct cryptocap *cap;
1045158702Spjd	u_int32_t hid;
1046104476Ssam	int result, hint;
1047104476Ssam
1048104628Ssam	CRYPTO_Q_LOCK();
1049104476Ssam	for (;;) {
1050104476Ssam		/*
1051104476Ssam		 * Find the first element in the queue that can be
1052104476Ssam		 * processed and look-ahead to see if multiple ops
1053104476Ssam		 * are ready for the same driver.
1054104476Ssam		 */
1055104476Ssam		submit = NULL;
1056104476Ssam		hint = 0;
1057104476Ssam		TAILQ_FOREACH(crp, &crp_q, crp_next) {
1058158702Spjd			hid = CRYPTO_SESID2HID(crp->crp_sid);
1059104476Ssam			cap = crypto_checkdriver(hid);
1060158702Spjd			/*
1061158702Spjd			 * Driver cannot disappeared when there is an active
1062158702Spjd			 * session.
1063158702Spjd			 */
1064158716Spjd			KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
1065158716Spjd			    __func__, __LINE__));
1066104476Ssam			if (cap == NULL || cap->cc_process == NULL) {
1067104476Ssam				/* Op needs to be migrated, process it. */
1068104476Ssam				if (submit == NULL)
1069104476Ssam					submit = crp;
1070104476Ssam				break;
1071104476Ssam			}
1072104476Ssam			if (!cap->cc_qblocked) {
1073104476Ssam				if (submit != NULL) {
1074104476Ssam					/*
1075104476Ssam					 * We stop on finding another op,
1076104476Ssam					 * regardless whether its for the same
1077104476Ssam					 * driver or not.  We could keep
1078104476Ssam					 * searching the queue but it might be
1079104476Ssam					 * better to just use a per-driver
1080104476Ssam					 * queue instead.
1081104476Ssam					 */
1082116924Ssam					if (CRYPTO_SESID2HID(submit->crp_sid) == hid)
1083104476Ssam						hint = CRYPTO_HINT_MORE;
1084104476Ssam					break;
1085104476Ssam				} else {
1086104476Ssam					submit = crp;
1087111297Ssam					if ((submit->crp_flags & CRYPTO_F_BATCH) == 0)
1088104476Ssam						break;
1089104476Ssam					/* keep scanning for more are q'd */
1090104476Ssam				}
1091104476Ssam			}
1092104476Ssam		}
1093104476Ssam		if (submit != NULL) {
1094104476Ssam			TAILQ_REMOVE(&crp_q, submit, crp_next);
1095158702Spjd			hid = CRYPTO_SESID2HID(submit->crp_sid);
1096158702Spjd			cap = crypto_checkdriver(hid);
1097158716Spjd			KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
1098158716Spjd			    __func__, __LINE__));
1099158702Spjd			result = crypto_invoke(cap, submit, hint);
1100104476Ssam			if (result == ERESTART) {
1101104476Ssam				/*
1102104476Ssam				 * The driver ran out of resources, mark the
1103104476Ssam				 * driver ``blocked'' for cryptop's and put
1104104476Ssam				 * the request back in the queue.  It would
1105104476Ssam				 * best to put the request back where we got
1106104476Ssam				 * it but that's hard so for now we put it
1107104476Ssam				 * at the front.  This should be ok; putting
1108104476Ssam				 * it at the end does not work.
1109104476Ssam				 */
1110104476Ssam				/* XXX validate sid again? */
1111116924Ssam				crypto_drivers[CRYPTO_SESID2HID(submit->crp_sid)].cc_qblocked = 1;
1112104476Ssam				TAILQ_INSERT_HEAD(&crp_q, submit, crp_next);
1113108587Ssam				cryptostats.cs_blocks++;
1114104476Ssam			}
1115104476Ssam		}
1116104476Ssam
1117104476Ssam		/* As above, but for key ops */
1118104476Ssam		TAILQ_FOREACH(krp, &crp_kq, krp_next) {
1119104476Ssam			cap = crypto_checkdriver(krp->krp_hid);
1120104476Ssam			if (cap == NULL || cap->cc_kprocess == NULL) {
1121104476Ssam				/* Op needs to be migrated, process it. */
1122104476Ssam				break;
1123104476Ssam			}
1124104476Ssam			if (!cap->cc_kqblocked)
1125104476Ssam				break;
1126104476Ssam		}
1127104476Ssam		if (krp != NULL) {
1128104476Ssam			TAILQ_REMOVE(&crp_kq, krp, krp_next);
1129158702Spjd			result = crypto_kinvoke(krp);
1130104476Ssam			if (result == ERESTART) {
1131104476Ssam				/*
1132104476Ssam				 * The driver ran out of resources, mark the
1133104476Ssam				 * driver ``blocked'' for cryptkop's and put
1134104476Ssam				 * the request back in the queue.  It would
1135104476Ssam				 * best to put the request back where we got
1136104476Ssam				 * it but that's hard so for now we put it
1137104476Ssam				 * at the front.  This should be ok; putting
1138104476Ssam				 * it at the end does not work.
1139104476Ssam				 */
1140104476Ssam				/* XXX validate sid again? */
1141104476Ssam				crypto_drivers[krp->krp_hid].cc_kqblocked = 1;
1142104476Ssam				TAILQ_INSERT_HEAD(&crp_kq, krp, krp_next);
1143108587Ssam				cryptostats.cs_kblocks++;
1144104476Ssam			}
1145104476Ssam		}
1146104476Ssam
1147104628Ssam		if (submit == NULL && krp == NULL) {
1148104476Ssam			/*
1149104476Ssam			 * Nothing more to be processed.  Sleep until we're
1150104476Ssam			 * woken because there are more ops to process.
1151104476Ssam			 * This happens either by submission or by a driver
1152104476Ssam			 * becoming unblocked and notifying us through
1153104476Ssam			 * crypto_unblock.  Note that when we wakeup we
1154104476Ssam			 * start processing each queue again from the
1155104476Ssam			 * front. It's not clear that it's important to
1156104476Ssam			 * preserve this ordering since ops may finish
1157104476Ssam			 * out of order if dispatched to different devices
1158104476Ssam			 * and some become blocked while others do not.
1159104476Ssam			 */
1160104628Ssam			msleep(&crp_q, &crypto_q_mtx, PWAIT, "crypto_wait", 0);
1161108588Ssam			if (cryptoproc == NULL)
1162108588Ssam				break;
1163108587Ssam			cryptostats.cs_intrs++;
1164104476Ssam		}
1165104476Ssam	}
1166108588Ssam	CRYPTO_Q_UNLOCK();
1167104628Ssam
1168108588Ssam	crypto_finis(&crp_q);
1169104628Ssam}
1170104628Ssam
1171104628Ssam/*
1172104628Ssam * Crypto returns thread, does callbacks for processed crypto requests.
1173104628Ssam * Callbacks are done here, rather than in the crypto drivers, because
1174104628Ssam * callbacks typically are expensive and would slow interrupt handling.
1175104628Ssam */
1176104628Ssamstatic void
1177104628Ssamcrypto_ret_proc(void)
1178104628Ssam{
1179104628Ssam	struct cryptop *crpt;
1180104628Ssam	struct cryptkop *krpt;
1181104628Ssam
1182104628Ssam	CRYPTO_RETQ_LOCK();
1183104628Ssam	for (;;) {
1184104628Ssam		/* Harvest return q's for completed ops */
1185104628Ssam		crpt = TAILQ_FIRST(&crp_ret_q);
1186104628Ssam		if (crpt != NULL)
1187104628Ssam			TAILQ_REMOVE(&crp_ret_q, crpt, crp_next);
1188104628Ssam
1189104628Ssam		krpt = TAILQ_FIRST(&crp_ret_kq);
1190104628Ssam		if (krpt != NULL)
1191104628Ssam			TAILQ_REMOVE(&crp_ret_kq, krpt, krp_next);
1192104628Ssam
1193104628Ssam		if (crpt != NULL || krpt != NULL) {
1194104628Ssam			CRYPTO_RETQ_UNLOCK();
1195104628Ssam			/*
1196104628Ssam			 * Run callbacks unlocked.
1197104628Ssam			 */
1198108587Ssam			if (crpt != NULL) {
1199108587Ssam#ifdef CRYPTO_TIMING
1200108587Ssam				if (crypto_timing) {
1201108587Ssam					/*
1202108587Ssam					 * NB: We must copy the timestamp before
1203108587Ssam					 * doing the callback as the cryptop is
1204108587Ssam					 * likely to be reclaimed.
1205108587Ssam					 */
1206108587Ssam					struct bintime t = crpt->crp_tstamp;
1207108587Ssam					crypto_tstat(&cryptostats.cs_cb, &t);
1208108587Ssam					crpt->crp_callback(crpt);
1209108587Ssam					crypto_tstat(&cryptostats.cs_finis, &t);
1210108587Ssam				} else
1211108587Ssam#endif
1212108587Ssam					crpt->crp_callback(crpt);
1213108587Ssam			}
1214104628Ssam			if (krpt != NULL)
1215104628Ssam				krpt->krp_callback(krpt);
1216104628Ssam			CRYPTO_RETQ_LOCK();
1217104628Ssam		} else {
1218104628Ssam			/*
1219104628Ssam			 * Nothing more to be processed.  Sleep until we're
1220104628Ssam			 * woken because there are more returns to process.
1221104628Ssam			 */
1222104628Ssam			msleep(&crp_ret_q, &crypto_ret_q_mtx, PWAIT,
1223104628Ssam				"crypto_ret_wait", 0);
1224108588Ssam			if (cryptoretproc == NULL)
1225108588Ssam				break;
1226108587Ssam			cryptostats.cs_rets++;
1227104628Ssam		}
1228104628Ssam	}
1229108588Ssam	CRYPTO_RETQ_UNLOCK();
1230108588Ssam
1231108588Ssam	crypto_finis(&crp_ret_q);
1232104628Ssam}
1233