crypto.c revision 158823
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 158823 2006-05-22 07:48:45Z 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)
82104476Ssam
83104476Ssamstatic	uma_zone_t cryptop_zone;
84104476Ssamstatic	uma_zone_t cryptodesc_zone;
85104476Ssam
86104476Ssamint	crypto_userasymcrypto = 1;	/* userland may do asym crypto reqs */
87104476SsamSYSCTL_INT(_kern, OID_AUTO, userasymcrypto, CTLFLAG_RW,
88104476Ssam	   &crypto_userasymcrypto, 0,
89104476Ssam	   "Enable/disable user-mode access to asymmetric crypto support");
90104476Ssamint	crypto_devallowsoft = 0;	/* only use hardware crypto for asym */
91104476SsamSYSCTL_INT(_kern, OID_AUTO, cryptodevallowsoft, CTLFLAG_RW,
92104476Ssam	   &crypto_devallowsoft, 0,
93104476Ssam	   "Enable/disable use of software asym crypto support");
94104476Ssam
95104476SsamMALLOC_DEFINE(M_CRYPTO_DATA, "crypto", "crypto session records");
96104476Ssam
97108588Ssamstatic	void crypto_proc(void);
98108588Ssamstatic	struct proc *cryptoproc;
99108588Ssamstatic	void crypto_ret_proc(void);
100108588Ssamstatic	struct proc *cryptoretproc;
101108588Ssamstatic	void crypto_destroy(void);
102158702Spjdstatic	int crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint);
103158702Spjdstatic	int crypto_kinvoke(struct cryptkop *krp);
104108588Ssam
105108587Ssamstatic	struct cryptostats cryptostats;
106108587SsamSYSCTL_STRUCT(_kern, OID_AUTO, crypto_stats, CTLFLAG_RW, &cryptostats,
107108587Ssam	    cryptostats, "Crypto system statistics");
108108587Ssam
109108587Ssam#ifdef CRYPTO_TIMING
110108587Ssamstatic	int crypto_timing = 0;
111108587SsamSYSCTL_INT(_debug, OID_AUTO, crypto_timing, CTLFLAG_RW,
112108587Ssam	   &crypto_timing, 0, "Enable/disable crypto timing support");
113108587Ssam#endif
114108587Ssam
115108588Ssamstatic int
116104476Ssamcrypto_init(void)
117104476Ssam{
118108588Ssam	int error;
119108588Ssam
120115746Ssam	mtx_init(&crypto_drivers_mtx, "crypto", "crypto driver table",
121115746Ssam		MTX_DEF|MTX_QUIET);
122108588Ssam
123108588Ssam	TAILQ_INIT(&crp_q);
124108588Ssam	TAILQ_INIT(&crp_kq);
125115746Ssam	mtx_init(&crypto_q_mtx, "crypto", "crypto op queues", MTX_DEF);
126108588Ssam
127108588Ssam	TAILQ_INIT(&crp_ret_q);
128108588Ssam	TAILQ_INIT(&crp_ret_kq);
129115746Ssam	mtx_init(&crypto_ret_q_mtx, "crypto", "crypto return queues", MTX_DEF);
130108588Ssam
131104476Ssam	cryptop_zone = uma_zcreate("cryptop", sizeof (struct cryptop),
132104476Ssam				    0, 0, 0, 0,
133104476Ssam				    UMA_ALIGN_PTR, UMA_ZONE_ZINIT);
134104476Ssam	cryptodesc_zone = uma_zcreate("cryptodesc", sizeof (struct cryptodesc),
135104476Ssam				    0, 0, 0, 0,
136104476Ssam				    UMA_ALIGN_PTR, UMA_ZONE_ZINIT);
137108588Ssam	if (cryptodesc_zone == NULL || cryptop_zone == NULL) {
138108588Ssam		printf("crypto_init: cannot setup crypto zones\n");
139108588Ssam		error = ENOMEM;
140108588Ssam		goto bad;
141108588Ssam	}
142104476Ssam
143104476Ssam	crypto_drivers_num = CRYPTO_DRIVERS_INITIAL;
144104476Ssam	crypto_drivers = malloc(crypto_drivers_num *
145104476Ssam	    sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT | M_ZERO);
146108588Ssam	if (crypto_drivers == NULL) {
147108588Ssam		printf("crypto_init: cannot setup crypto drivers\n");
148108588Ssam		error = ENOMEM;
149108588Ssam		goto bad;
150108588Ssam	}
151104476Ssam
152108588Ssam	error = kthread_create((void (*)(void *)) crypto_proc, NULL,
153108588Ssam		    &cryptoproc, 0, 0, "crypto");
154108588Ssam	if (error) {
155108588Ssam		printf("crypto_init: cannot start crypto thread; error %d",
156108588Ssam			error);
157108588Ssam		goto bad;
158108588Ssam	}
159104476Ssam
160108588Ssam	error = kthread_create((void (*)(void *)) crypto_ret_proc, NULL,
161108588Ssam		    &cryptoretproc, 0, 0, "crypto returns");
162108588Ssam	if (error) {
163108588Ssam		printf("crypto_init: cannot start cryptoret thread; error %d",
164108588Ssam			error);
165108588Ssam		goto bad;
166108588Ssam	}
167108588Ssam	return 0;
168108588Ssambad:
169108588Ssam	crypto_destroy();
170108588Ssam	return error;
171104476Ssam}
172104476Ssam
173104476Ssam/*
174108588Ssam * Signal a crypto thread to terminate.  We use the driver
175108588Ssam * table lock to synchronize the sleep/wakeups so that we
176108588Ssam * are sure the threads have terminated before we release
177108588Ssam * the data structures they use.  See crypto_finis below
178108588Ssam * for the other half of this song-and-dance.
179108588Ssam */
180108588Ssamstatic void
181108588Ssamcrypto_terminate(struct proc **pp, void *q)
182108588Ssam{
183108588Ssam	struct proc *p;
184108588Ssam
185108588Ssam	mtx_assert(&crypto_drivers_mtx, MA_OWNED);
186108588Ssam	p = *pp;
187108588Ssam	*pp = NULL;
188108588Ssam	if (p) {
189108588Ssam		wakeup_one(q);
190108588Ssam		PROC_LOCK(p);		/* NB: insure we don't miss wakeup */
191108588Ssam		CRYPTO_DRIVER_UNLOCK();	/* let crypto_finis progress */
192108588Ssam		msleep(p, &p->p_mtx, PWAIT, "crypto_destroy", 0);
193108588Ssam		PROC_UNLOCK(p);
194108588Ssam		CRYPTO_DRIVER_LOCK();
195108588Ssam	}
196108588Ssam}
197108588Ssam
198108588Ssamstatic void
199108588Ssamcrypto_destroy(void)
200108588Ssam{
201108588Ssam	/*
202108588Ssam	 * Terminate any crypto threads.
203108588Ssam	 */
204108588Ssam	CRYPTO_DRIVER_LOCK();
205108588Ssam	crypto_terminate(&cryptoproc, &crp_q);
206108588Ssam	crypto_terminate(&cryptoretproc, &crp_ret_q);
207108588Ssam	CRYPTO_DRIVER_UNLOCK();
208108588Ssam
209108588Ssam	/* XXX flush queues??? */
210108588Ssam
211108588Ssam	/*
212108588Ssam	 * Reclaim dynamically allocated resources.
213108588Ssam	 */
214108588Ssam	if (crypto_drivers != NULL)
215108588Ssam		free(crypto_drivers, M_CRYPTO_DATA);
216108588Ssam
217108588Ssam	if (cryptodesc_zone != NULL)
218108588Ssam		uma_zdestroy(cryptodesc_zone);
219108588Ssam	if (cryptop_zone != NULL)
220108588Ssam		uma_zdestroy(cryptop_zone);
221108588Ssam	mtx_destroy(&crypto_q_mtx);
222108588Ssam	mtx_destroy(&crypto_ret_q_mtx);
223108588Ssam	mtx_destroy(&crypto_drivers_mtx);
224108588Ssam}
225108588Ssam
226108588Ssam/*
227105251Smarkm * Initialization code, both for static and dynamic loading.
228105251Smarkm */
229105251Smarkmstatic int
230105251Smarkmcrypto_modevent(module_t mod, int type, void *unused)
231105251Smarkm{
232108588Ssam	int error = EINVAL;
233108588Ssam
234105251Smarkm	switch (type) {
235105251Smarkm	case MOD_LOAD:
236108588Ssam		error = crypto_init();
237108588Ssam		if (error == 0 && bootverbose)
238105251Smarkm			printf("crypto: <crypto core>\n");
239108588Ssam		break;
240105251Smarkm	case MOD_UNLOAD:
241105251Smarkm		/*XXX disallow if active sessions */
242108588Ssam		error = 0;
243108588Ssam		crypto_destroy();
244105251Smarkm		return 0;
245105251Smarkm	}
246108588Ssam	return error;
247105251Smarkm}
248105251Smarkm
249105251Smarkmstatic moduledata_t crypto_mod = {
250105251Smarkm	"crypto",
251105251Smarkm	crypto_modevent,
252105251Smarkm	0
253105251Smarkm};
254105251SmarkmMODULE_VERSION(crypto, 1);
255106676SsamDECLARE_MODULE(crypto, crypto_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
256156281SwkoszekMODULE_DEPEND(crypto, zlib, 1, 1, 1);
257105251Smarkm
258105251Smarkm/*
259104476Ssam * Create a new session.
260104476Ssam */
261104476Ssamint
262104476Ssamcrypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard)
263104476Ssam{
264104476Ssam	struct cryptoini *cr;
265104476Ssam	u_int32_t hid, lid;
266104476Ssam	int err = EINVAL;
267104476Ssam
268104476Ssam	CRYPTO_DRIVER_LOCK();
269104476Ssam
270104476Ssam	if (crypto_drivers == NULL)
271104476Ssam		goto done;
272104476Ssam
273104476Ssam	/*
274104476Ssam	 * The algorithm we use here is pretty stupid; just use the
275104476Ssam	 * first driver that supports all the algorithms we need.
276104476Ssam	 *
277104476Ssam	 * XXX We need more smarts here (in real life too, but that's
278104476Ssam	 * XXX another story altogether).
279104476Ssam	 */
280104476Ssam
281104476Ssam	for (hid = 0; hid < crypto_drivers_num; hid++) {
282116924Ssam		struct cryptocap *cap = &crypto_drivers[hid];
283104476Ssam		/*
284104476Ssam		 * If it's not initialized or has remaining sessions
285104476Ssam		 * referencing it, skip.
286104476Ssam		 */
287116924Ssam		if (cap->cc_newsession == NULL ||
288116924Ssam		    (cap->cc_flags & CRYPTOCAP_F_CLEANUP))
289104476Ssam			continue;
290104476Ssam
291104476Ssam		/* Hardware required -- ignore software drivers. */
292116924Ssam		if (hard > 0 && (cap->cc_flags & CRYPTOCAP_F_SOFTWARE))
293104476Ssam			continue;
294104476Ssam		/* Software required -- ignore hardware drivers. */
295116924Ssam		if (hard < 0 && (cap->cc_flags & CRYPTOCAP_F_SOFTWARE) == 0)
296104476Ssam			continue;
297104476Ssam
298104476Ssam		/* See if all the algorithms are supported. */
299104476Ssam		for (cr = cri; cr; cr = cr->cri_next)
300116924Ssam			if (cap->cc_alg[cr->cri_alg] == 0)
301104476Ssam				break;
302104476Ssam
303104476Ssam		if (cr == NULL) {
304104476Ssam			/* Ok, all algorithms are supported. */
305104476Ssam
306104476Ssam			/*
307104476Ssam			 * Can't do everything in one session.
308104476Ssam			 *
309104476Ssam			 * XXX Fix this. We need to inject a "virtual" session layer right
310104476Ssam			 * XXX about here.
311104476Ssam			 */
312104476Ssam
313104476Ssam			/* Call the driver initialization routine. */
314104476Ssam			lid = hid;		/* Pass the driver ID. */
315116924Ssam			err = (*cap->cc_newsession)(cap->cc_arg, &lid, cri);
316104476Ssam			if (err == 0) {
317116924Ssam				/* XXX assert (hid &~ 0xffffff) == 0 */
318116924Ssam				/* XXX assert (cap->cc_flags &~ 0xff) == 0 */
319116924Ssam				(*sid) = ((cap->cc_flags & 0xff) << 24) | hid;
320104476Ssam				(*sid) <<= 32;
321104476Ssam				(*sid) |= (lid & 0xffffffff);
322116924Ssam				cap->cc_sessions++;
323104476Ssam			}
324104476Ssam			break;
325104476Ssam		}
326104476Ssam	}
327104476Ssamdone:
328104476Ssam	CRYPTO_DRIVER_UNLOCK();
329104476Ssam	return err;
330104476Ssam}
331104476Ssam
332158702Spjdstatic void
333158702Spjdcrypto_remove(struct cryptocap *cap)
334158702Spjd{
335158702Spjd
336158702Spjd	mtx_assert(&crypto_drivers_mtx, MA_OWNED);
337158702Spjd	if (cap->cc_sessions == 0 && cap->cc_koperations == 0)
338158702Spjd		bzero(cap, sizeof(*cap));
339158702Spjd}
340158702Spjd
341104476Ssam/*
342104476Ssam * Delete an existing session (or a reserved session on an unregistered
343104476Ssam * driver).
344104476Ssam */
345104476Ssamint
346104476Ssamcrypto_freesession(u_int64_t sid)
347104476Ssam{
348158702Spjd	struct cryptocap *cap;
349104476Ssam	u_int32_t hid;
350104476Ssam	int err;
351104476Ssam
352104476Ssam	CRYPTO_DRIVER_LOCK();
353104476Ssam
354104476Ssam	if (crypto_drivers == NULL) {
355104476Ssam		err = EINVAL;
356104476Ssam		goto done;
357104476Ssam	}
358104476Ssam
359104476Ssam	/* Determine two IDs. */
360116924Ssam	hid = CRYPTO_SESID2HID(sid);
361104476Ssam
362104476Ssam	if (hid >= crypto_drivers_num) {
363104476Ssam		err = ENOENT;
364104476Ssam		goto done;
365104476Ssam	}
366158702Spjd	cap = &crypto_drivers[hid];
367104476Ssam
368158702Spjd	if (cap->cc_sessions)
369158702Spjd		cap->cc_sessions--;
370104476Ssam
371104476Ssam	/* Call the driver cleanup routine, if available. */
372158702Spjd	if (cap->cc_freesession)
373158702Spjd		err = cap->cc_freesession(cap->cc_arg, sid);
374104476Ssam	else
375104476Ssam		err = 0;
376104476Ssam
377158702Spjd	if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
378158702Spjd		crypto_remove(cap);
379104476Ssam
380104476Ssamdone:
381104476Ssam	CRYPTO_DRIVER_UNLOCK();
382104476Ssam	return err;
383104476Ssam}
384104476Ssam
385104476Ssam/*
386104476Ssam * Return an unused driver id.  Used by drivers prior to registering
387104476Ssam * support for the algorithms they handle.
388104476Ssam */
389104476Ssamint32_t
390104476Ssamcrypto_get_driverid(u_int32_t flags)
391104476Ssam{
392104476Ssam	struct cryptocap *newdrv;
393104476Ssam	int i;
394104476Ssam
395104476Ssam	CRYPTO_DRIVER_LOCK();
396104476Ssam
397158702Spjd	for (i = 0; i < crypto_drivers_num; i++) {
398104476Ssam		if (crypto_drivers[i].cc_process == NULL &&
399158702Spjd		    (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0) {
400104476Ssam			break;
401158702Spjd		}
402158702Spjd	}
403104476Ssam
404104476Ssam	/* Out of entries, allocate some more. */
405104476Ssam	if (i == crypto_drivers_num) {
406104476Ssam		/* Be careful about wrap-around. */
407104476Ssam		if (2 * crypto_drivers_num <= crypto_drivers_num) {
408104476Ssam			CRYPTO_DRIVER_UNLOCK();
409104476Ssam			printf("crypto: driver count wraparound!\n");
410104476Ssam			return -1;
411104476Ssam		}
412104476Ssam
413104476Ssam		newdrv = malloc(2 * crypto_drivers_num *
414104476Ssam		    sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
415104476Ssam		if (newdrv == NULL) {
416104476Ssam			CRYPTO_DRIVER_UNLOCK();
417104476Ssam			printf("crypto: no space to expand driver table!\n");
418104476Ssam			return -1;
419104476Ssam		}
420104476Ssam
421104476Ssam		bcopy(crypto_drivers, newdrv,
422104476Ssam		    crypto_drivers_num * sizeof(struct cryptocap));
423104476Ssam
424104476Ssam		crypto_drivers_num *= 2;
425104476Ssam
426104476Ssam		free(crypto_drivers, M_CRYPTO_DATA);
427104476Ssam		crypto_drivers = newdrv;
428104476Ssam	}
429104476Ssam
430104476Ssam	/* NB: state is zero'd on free */
431104476Ssam	crypto_drivers[i].cc_sessions = 1;	/* Mark */
432104476Ssam	crypto_drivers[i].cc_flags = flags;
433104476Ssam	if (bootverbose)
434104476Ssam		printf("crypto: assign driver %u, flags %u\n", i, flags);
435104476Ssam
436104476Ssam	CRYPTO_DRIVER_UNLOCK();
437104476Ssam
438104476Ssam	return i;
439104476Ssam}
440104476Ssam
441104476Ssamstatic struct cryptocap *
442104476Ssamcrypto_checkdriver(u_int32_t hid)
443104476Ssam{
444104476Ssam	if (crypto_drivers == NULL)
445104476Ssam		return NULL;
446104476Ssam	return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]);
447104476Ssam}
448104476Ssam
449104476Ssam/*
450104476Ssam * Register support for a key-related algorithm.  This routine
451104476Ssam * is called once for each algorithm supported a driver.
452104476Ssam */
453104476Ssamint
454104476Ssamcrypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags,
455104476Ssam    int (*kprocess)(void*, struct cryptkop *, int),
456104476Ssam    void *karg)
457104476Ssam{
458104476Ssam	struct cryptocap *cap;
459104476Ssam	int err;
460104476Ssam
461104476Ssam	CRYPTO_DRIVER_LOCK();
462104476Ssam
463104476Ssam	cap = crypto_checkdriver(driverid);
464104476Ssam	if (cap != NULL &&
465104476Ssam	    (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) {
466104476Ssam		/*
467104476Ssam		 * XXX Do some performance testing to determine placing.
468104476Ssam		 * XXX We probably need an auxiliary data structure that
469104476Ssam		 * XXX describes relative performances.
470104476Ssam		 */
471104476Ssam
472104476Ssam		cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
473104476Ssam		if (bootverbose)
474104476Ssam			printf("crypto: driver %u registers key alg %u flags %u\n"
475104476Ssam				, driverid
476104476Ssam				, kalg
477104476Ssam				, flags
478104476Ssam			);
479104476Ssam
480104476Ssam		if (cap->cc_kprocess == NULL) {
481104476Ssam			cap->cc_karg = karg;
482104476Ssam			cap->cc_kprocess = kprocess;
483104476Ssam		}
484104476Ssam		err = 0;
485104476Ssam	} else
486104476Ssam		err = EINVAL;
487104476Ssam
488104476Ssam	CRYPTO_DRIVER_UNLOCK();
489104476Ssam	return err;
490104476Ssam}
491104476Ssam
492104476Ssam/*
493104476Ssam * Register support for a non-key-related algorithm.  This routine
494104476Ssam * is called once for each such algorithm supported by a driver.
495104476Ssam */
496104476Ssamint
497104476Ssamcrypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
498104476Ssam    u_int32_t flags,
499104476Ssam    int (*newses)(void*, u_int32_t*, struct cryptoini*),
500104476Ssam    int (*freeses)(void*, u_int64_t),
501104476Ssam    int (*process)(void*, struct cryptop *, int),
502104476Ssam    void *arg)
503104476Ssam{
504104476Ssam	struct cryptocap *cap;
505104476Ssam	int err;
506104476Ssam
507104476Ssam	CRYPTO_DRIVER_LOCK();
508104476Ssam
509104476Ssam	cap = crypto_checkdriver(driverid);
510104476Ssam	/* NB: algorithms are in the range [1..max] */
511104476Ssam	if (cap != NULL &&
512104476Ssam	    (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) {
513104476Ssam		/*
514104476Ssam		 * XXX Do some performance testing to determine placing.
515104476Ssam		 * XXX We probably need an auxiliary data structure that
516104476Ssam		 * XXX describes relative performances.
517104476Ssam		 */
518104476Ssam
519104476Ssam		cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
520104476Ssam		cap->cc_max_op_len[alg] = maxoplen;
521104476Ssam		if (bootverbose)
522104476Ssam			printf("crypto: driver %u registers alg %u flags %u maxoplen %u\n"
523104476Ssam				, driverid
524104476Ssam				, alg
525104476Ssam				, flags
526104476Ssam				, maxoplen
527104476Ssam			);
528104476Ssam
529104476Ssam		if (cap->cc_process == NULL) {
530104476Ssam			cap->cc_arg = arg;
531104476Ssam			cap->cc_newsession = newses;
532104476Ssam			cap->cc_process = process;
533104476Ssam			cap->cc_freesession = freeses;
534104476Ssam			cap->cc_sessions = 0;		/* Unmark */
535104476Ssam		}
536104476Ssam		err = 0;
537104476Ssam	} else
538104476Ssam		err = EINVAL;
539104476Ssam
540104476Ssam	CRYPTO_DRIVER_UNLOCK();
541104476Ssam	return err;
542104476Ssam}
543104476Ssam
544104476Ssam/*
545104476Ssam * Unregister a crypto driver. If there are pending sessions using it,
546104476Ssam * leave enough information around so that subsequent calls using those
547104476Ssam * sessions will correctly detect the driver has been unregistered and
548104476Ssam * reroute requests.
549104476Ssam */
550104476Ssamint
551104476Ssamcrypto_unregister(u_int32_t driverid, int alg)
552104476Ssam{
553158702Spjd	struct cryptocap *cap;
554158702Spjd	u_int32_t ses, kops;
555104476Ssam	int i, err;
556104476Ssam
557104476Ssam	CRYPTO_DRIVER_LOCK();
558104476Ssam
559104476Ssam	cap = crypto_checkdriver(driverid);
560104476Ssam	if (cap != NULL &&
561104476Ssam	    (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) &&
562104476Ssam	    cap->cc_alg[alg] != 0) {
563104476Ssam		cap->cc_alg[alg] = 0;
564104476Ssam		cap->cc_max_op_len[alg] = 0;
565104476Ssam
566104476Ssam		/* Was this the last algorithm ? */
567104476Ssam		for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
568104476Ssam			if (cap->cc_alg[i] != 0)
569104476Ssam				break;
570104476Ssam
571104476Ssam		if (i == CRYPTO_ALGORITHM_MAX + 1) {
572104476Ssam			ses = cap->cc_sessions;
573158702Spjd			kops = cap->cc_koperations;
574158702Spjd			bzero(cap, sizeof(*cap));
575158702Spjd			if (ses != 0 || kops != 0) {
576104476Ssam				/*
577104476Ssam				 * If there are pending sessions, just mark as invalid.
578104476Ssam				 */
579104476Ssam				cap->cc_flags |= CRYPTOCAP_F_CLEANUP;
580104476Ssam				cap->cc_sessions = ses;
581158702Spjd				cap->cc_koperations = kops;
582104476Ssam			}
583104476Ssam		}
584104476Ssam		err = 0;
585104476Ssam	} else
586104476Ssam		err = EINVAL;
587104476Ssam
588104476Ssam	CRYPTO_DRIVER_UNLOCK();
589104476Ssam	return err;
590104476Ssam}
591104476Ssam
592104476Ssam/*
593104476Ssam * Unregister all algorithms associated with a crypto driver.
594104476Ssam * If there are pending sessions using it, leave enough information
595104476Ssam * around so that subsequent calls using those sessions will
596104476Ssam * correctly detect the driver has been unregistered and reroute
597104476Ssam * requests.
598104476Ssam */
599104476Ssamint
600104476Ssamcrypto_unregister_all(u_int32_t driverid)
601104476Ssam{
602158702Spjd	struct cryptocap *cap;
603158702Spjd	u_int32_t ses, kops;
604104476Ssam	int i, err;
605104476Ssam
606104476Ssam	CRYPTO_DRIVER_LOCK();
607104476Ssam
608104476Ssam	cap = crypto_checkdriver(driverid);
609104476Ssam	if (cap != NULL) {
610104476Ssam		for (i = CRYPTO_ALGORITHM_MIN; i <= CRYPTO_ALGORITHM_MAX; i++) {
611104476Ssam			cap->cc_alg[i] = 0;
612104476Ssam			cap->cc_max_op_len[i] = 0;
613104476Ssam		}
614104476Ssam		ses = cap->cc_sessions;
615158702Spjd		kops = cap->cc_koperations;
616158702Spjd		bzero(cap, sizeof(*cap));
617158702Spjd		if (ses != 0 || kops != 0) {
618104476Ssam			/*
619104476Ssam			 * If there are pending sessions, just mark as invalid.
620104476Ssam			 */
621104476Ssam			cap->cc_flags |= CRYPTOCAP_F_CLEANUP;
622104476Ssam			cap->cc_sessions = ses;
623158702Spjd			cap->cc_koperations = kops;
624104476Ssam		}
625104476Ssam		err = 0;
626104476Ssam	} else
627104476Ssam		err = EINVAL;
628104476Ssam
629104476Ssam	CRYPTO_DRIVER_UNLOCK();
630104476Ssam	return err;
631104476Ssam}
632104476Ssam
633104476Ssam/*
634104476Ssam * Clear blockage on a driver.  The what parameter indicates whether
635104476Ssam * the driver is now ready for cryptop's and/or cryptokop's.
636104476Ssam */
637104476Ssamint
638104476Ssamcrypto_unblock(u_int32_t driverid, int what)
639104476Ssam{
640104476Ssam	struct cryptocap *cap;
641104476Ssam	int needwakeup, err;
642104476Ssam
643104476Ssam	CRYPTO_Q_LOCK();
644104476Ssam	cap = crypto_checkdriver(driverid);
645104476Ssam	if (cap != NULL) {
646104628Ssam		needwakeup = 0;
647104476Ssam		if (what & CRYPTO_SYMQ) {
648104476Ssam			needwakeup |= cap->cc_qblocked;
649104476Ssam			cap->cc_qblocked = 0;
650104476Ssam		}
651104476Ssam		if (what & CRYPTO_ASYMQ) {
652104476Ssam			needwakeup |= cap->cc_kqblocked;
653104476Ssam			cap->cc_kqblocked = 0;
654104476Ssam		}
655104628Ssam		if (needwakeup)
656104628Ssam			wakeup_one(&crp_q);
657104476Ssam		err = 0;
658104476Ssam	} else
659104476Ssam		err = EINVAL;
660104476Ssam	CRYPTO_Q_UNLOCK();
661104476Ssam
662104476Ssam	return err;
663104476Ssam}
664104476Ssam
665104476Ssam/*
666104476Ssam * Add a crypto request to a queue, to be processed by the kernel thread.
667104476Ssam */
668104476Ssamint
669104476Ssamcrypto_dispatch(struct cryptop *crp)
670104476Ssam{
671158702Spjd	struct cryptocap *cap;
672158702Spjd	u_int32_t hid;
673158702Spjd	int result;
674104476Ssam
675108587Ssam	cryptostats.cs_ops++;
676108587Ssam
677108587Ssam#ifdef CRYPTO_TIMING
678108587Ssam	if (crypto_timing)
679108587Ssam		binuptime(&crp->crp_tstamp);
680108587Ssam#endif
681108587Ssam
682158702Spjd	hid = CRYPTO_SESID2HID(crp->crp_sid);
683158702Spjd
684111297Ssam	if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) {
685111297Ssam		/*
686111297Ssam		 * Caller marked the request to be processed
687111297Ssam		 * immediately; dispatch it directly to the
688111297Ssam		 * driver unless the driver is currently blocked.
689111297Ssam		 */
690111297Ssam		cap = crypto_checkdriver(hid);
691158702Spjd		/* Driver cannot disappeared when there is an active session. */
692158702Spjd		KASSERT(cap != NULL, ("%s: Driver disappeared.", __func__));
693158702Spjd		if (!cap->cc_qblocked) {
694158702Spjd			result = crypto_invoke(cap, crp, 0);
695158702Spjd			if (result != ERESTART)
696158702Spjd				return (result);
697158823Spjd			/*
698158823Spjd			 * The driver ran out of resources, put the request on
699158823Spjd			 * the queue.
700158823Spjd			 */
701108990Ssam		}
702108990Ssam	}
703158702Spjd	CRYPTO_Q_LOCK();
704158702Spjd	if (CRYPTO_Q_EMPTY())
705157665Spjd		wakeup_one(&crp_q);
706158702Spjd	TAILQ_INSERT_TAIL(&crp_q, crp, crp_next);
707115746Ssam	CRYPTO_Q_UNLOCK();
708158702Spjd	return 0;
709104476Ssam}
710104476Ssam
711104476Ssam/*
712104476Ssam * Add an asymetric crypto request to a queue,
713104476Ssam * to be processed by the kernel thread.
714104476Ssam */
715104476Ssamint
716104476Ssamcrypto_kdispatch(struct cryptkop *krp)
717104476Ssam{
718158702Spjd	int result;
719104476Ssam
720108587Ssam	cryptostats.cs_kops++;
721108587Ssam
722158702Spjd	result = crypto_kinvoke(krp);
723158702Spjd	if (result != ERESTART)
724158702Spjd		return (result);
725104476Ssam	CRYPTO_Q_LOCK();
726158702Spjd	if (CRYPTO_Q_EMPTY())
727157665Spjd		wakeup_one(&crp_q);
728158702Spjd	TAILQ_INSERT_TAIL(&crp_kq, krp, krp_next);
729104476Ssam	CRYPTO_Q_UNLOCK();
730104476Ssam
731158702Spjd	return 0;
732104476Ssam}
733104476Ssam
734104476Ssam/*
735104476Ssam * Dispatch an assymetric crypto request to the appropriate crypto devices.
736104476Ssam */
737104476Ssamstatic int
738158702Spjdcrypto_kinvoke(struct cryptkop *krp)
739104476Ssam{
740158702Spjd	struct cryptocap *cap = NULL;
741104476Ssam	u_int32_t hid;
742158702Spjd	int error = 0;
743104476Ssam
744158702Spjd	KASSERT(krp != NULL, ("%s: krp == NULL", __func__));
745158702Spjd	KASSERT(krp->krp_callback != NULL,
746158702Spjd	    ("%s: krp->crp_callback == NULL", __func__));
747104476Ssam
748158702Spjd	CRYPTO_DRIVER_LOCK();
749104476Ssam	for (hid = 0; hid < crypto_drivers_num; hid++) {
750158702Spjd		cap = &crypto_drivers[hid];
751158702Spjd		if (cap == NULL)
752104476Ssam			continue;
753158702Spjd		if ((cap->cc_flags & CRYPTOCAP_F_SOFTWARE) &&
754158702Spjd		    !crypto_devallowsoft) {
755104476Ssam			continue;
756158702Spjd		}
757158702Spjd		if (cap->cc_kprocess == NULL)
758104476Ssam			continue;
759158702Spjd		if (!(cap->cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED))
760158702Spjd			continue;
761158702Spjd		if (cap->cc_kqblocked) {
762158702Spjd			error = ERESTART;
763158702Spjd			continue;
764158702Spjd		}
765158702Spjd		error = 0;
766104476Ssam		break;
767104476Ssam	}
768158702Spjd	krp->krp_hid = hid;
769104476Ssam	if (hid < crypto_drivers_num) {
770158702Spjd		cap->cc_koperations++;
771158702Spjd		CRYPTO_DRIVER_UNLOCK();
772158702Spjd		error = cap->cc_kprocess(cap->cc_karg, krp, 0);
773158702Spjd		CRYPTO_DRIVER_LOCK();
774158702Spjd		if (error == ERESTART) {
775158702Spjd			cap->cc_koperations--;
776158702Spjd			cap->cc_kqblocked = 1;
777158702Spjd			CRYPTO_DRIVER_UNLOCK();
778158702Spjd			cryptostats.cs_kblocks++;
779158702Spjd			return (error);
780158702Spjd		}
781158702Spjd	} else {
782104476Ssam		error = ENODEV;
783158702Spjd	}
784158702Spjd	CRYPTO_DRIVER_UNLOCK();
785104476Ssam
786104476Ssam	if (error) {
787104476Ssam		krp->krp_status = error;
788104628Ssam		crypto_kdone(krp);
789104476Ssam	}
790104476Ssam	return 0;
791104476Ssam}
792104476Ssam
793108587Ssam#ifdef CRYPTO_TIMING
794108587Ssamstatic void
795108587Ssamcrypto_tstat(struct cryptotstat *ts, struct bintime *bt)
796108587Ssam{
797108587Ssam	struct bintime now, delta;
798108587Ssam	struct timespec t;
799108587Ssam	uint64_t u;
800108587Ssam
801108587Ssam	binuptime(&now);
802108587Ssam	u = now.frac;
803108587Ssam	delta.frac = now.frac - bt->frac;
804108587Ssam	delta.sec = now.sec - bt->sec;
805108587Ssam	if (u < delta.frac)
806108587Ssam		delta.sec--;
807108587Ssam	bintime2timespec(&delta, &t);
808108587Ssam	timespecadd(&ts->acc, &t);
809108587Ssam	if (timespeccmp(&t, &ts->min, <))
810108587Ssam		ts->min = t;
811108587Ssam	if (timespeccmp(&t, &ts->max, >))
812108587Ssam		ts->max = t;
813108587Ssam	ts->count++;
814108587Ssam
815108587Ssam	*bt = now;
816108587Ssam}
817108587Ssam#endif
818108587Ssam
819104476Ssam/*
820104476Ssam * Dispatch a crypto request to the appropriate crypto devices.
821104476Ssam */
822104476Ssamstatic int
823158702Spjdcrypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint)
824104476Ssam{
825104476Ssam
826158702Spjd	KASSERT(crp != NULL, ("%s: crp == NULL", __func__));
827158702Spjd	KASSERT(crp->crp_callback != NULL,
828158702Spjd	    ("%s: crp->crp_callback == NULL", __func__));
829158702Spjd	KASSERT(crp->crp_desc != NULL, ("%s: crp->crp_desc == NULL", __func__));
830158702Spjd
831108587Ssam#ifdef CRYPTO_TIMING
832108587Ssam	if (crypto_timing)
833108587Ssam		crypto_tstat(&cryptostats.cs_invoke, &crp->crp_tstamp);
834108587Ssam#endif
835158702Spjd	if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) {
836104476Ssam		struct cryptodesc *crd;
837104476Ssam		u_int64_t nid;
838104476Ssam
839104476Ssam		/*
840104476Ssam		 * Driver has unregistered; migrate the session and return
841104476Ssam		 * an error to the caller so they'll resubmit the op.
842158702Spjd		 *
843158702Spjd		 * XXX: What if there are more already queued requests for this
844158702Spjd		 *      session?
845104476Ssam		 */
846158702Spjd		crypto_freesession(crp->crp_sid);
847158702Spjd
848104476Ssam		for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
849104476Ssam			crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
850104476Ssam
851104476Ssam		if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0)
852104476Ssam			crp->crp_sid = nid;
853104476Ssam
854104476Ssam		crp->crp_etype = EAGAIN;
855104628Ssam		crypto_done(crp);
856104476Ssam		return 0;
857104476Ssam	} else {
858104476Ssam		/*
859104476Ssam		 * Invoke the driver to process the request.
860104476Ssam		 */
861158702Spjd		return cap->cc_process(cap->cc_arg, crp, hint);
862104476Ssam	}
863104476Ssam}
864104476Ssam
865104476Ssam/*
866104476Ssam * Release a set of crypto descriptors.
867104476Ssam */
868104476Ssamvoid
869104476Ssamcrypto_freereq(struct cryptop *crp)
870104476Ssam{
871104476Ssam	struct cryptodesc *crd;
872104476Ssam
873104476Ssam	if (crp == NULL)
874104476Ssam		return;
875104476Ssam
876104476Ssam	while ((crd = crp->crp_desc) != NULL) {
877104476Ssam		crp->crp_desc = crd->crd_next;
878104476Ssam		uma_zfree(cryptodesc_zone, crd);
879104476Ssam	}
880104476Ssam
881104476Ssam	uma_zfree(cryptop_zone, crp);
882104476Ssam}
883104476Ssam
884104476Ssam/*
885104476Ssam * Acquire a set of crypto descriptors.
886104476Ssam */
887104476Ssamstruct cryptop *
888104476Ssamcrypto_getreq(int num)
889104476Ssam{
890104476Ssam	struct cryptodesc *crd;
891104476Ssam	struct cryptop *crp;
892104476Ssam
893108813Ssam	crp = uma_zalloc(cryptop_zone, M_NOWAIT|M_ZERO);
894104476Ssam	if (crp != NULL) {
895104476Ssam		while (num--) {
896108813Ssam			crd = uma_zalloc(cryptodesc_zone, M_NOWAIT|M_ZERO);
897104476Ssam			if (crd == NULL) {
898104476Ssam				crypto_freereq(crp);
899104476Ssam				return NULL;
900104476Ssam			}
901104476Ssam
902104476Ssam			crd->crd_next = crp->crp_desc;
903104476Ssam			crp->crp_desc = crd;
904104476Ssam		}
905104476Ssam	}
906104476Ssam	return crp;
907104476Ssam}
908104476Ssam
909104476Ssam/*
910104476Ssam * Invoke the callback on behalf of the driver.
911104476Ssam */
912104476Ssamvoid
913104476Ssamcrypto_done(struct cryptop *crp)
914104476Ssam{
915115746Ssam	KASSERT((crp->crp_flags & CRYPTO_F_DONE) == 0,
916115746Ssam		("crypto_done: op already done, flags 0x%x", crp->crp_flags));
917115746Ssam	crp->crp_flags |= CRYPTO_F_DONE;
918108587Ssam	if (crp->crp_etype != 0)
919108587Ssam		cryptostats.cs_errs++;
920108587Ssam#ifdef CRYPTO_TIMING
921108587Ssam	if (crypto_timing)
922108587Ssam		crypto_tstat(&cryptostats.cs_done, &crp->crp_tstamp);
923108587Ssam#endif
924117058Ssam	/*
925117058Ssam	 * CBIMM means unconditionally do the callback immediately;
926117058Ssam	 * CBIFSYNC means do the callback immediately only if the
927117058Ssam	 * operation was done synchronously.  Both are used to avoid
928117058Ssam	 * doing extraneous context switches; the latter is mostly
929117058Ssam	 * used with the software crypto driver.
930117058Ssam	 */
931117058Ssam	if ((crp->crp_flags & CRYPTO_F_CBIMM) ||
932117058Ssam	    ((crp->crp_flags & CRYPTO_F_CBIFSYNC) &&
933117058Ssam	     (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) {
934111297Ssam		/*
935111297Ssam		 * Do the callback directly.  This is ok when the
936111297Ssam		 * callback routine does very little (e.g. the
937111297Ssam		 * /dev/crypto callback method just does a wakeup).
938111297Ssam		 */
939111297Ssam#ifdef CRYPTO_TIMING
940111297Ssam		if (crypto_timing) {
941111297Ssam			/*
942111297Ssam			 * NB: We must copy the timestamp before
943111297Ssam			 * doing the callback as the cryptop is
944111297Ssam			 * likely to be reclaimed.
945111297Ssam			 */
946111297Ssam			struct bintime t = crp->crp_tstamp;
947111297Ssam			crypto_tstat(&cryptostats.cs_cb, &t);
948111297Ssam			crp->crp_callback(crp);
949111297Ssam			crypto_tstat(&cryptostats.cs_finis, &t);
950111297Ssam		} else
951111297Ssam#endif
952111297Ssam			crp->crp_callback(crp);
953111297Ssam	} else {
954111297Ssam		/*
955111297Ssam		 * Normal case; queue the callback for the thread.
956111297Ssam		 */
957111297Ssam		CRYPTO_RETQ_LOCK();
958158702Spjd		if (TAILQ_EMPTY(&crp_ret_q))
959158702Spjd			wakeup_one(&crp_ret_q);	/* shared wait channel */
960111297Ssam		TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next);
961111297Ssam		CRYPTO_RETQ_UNLOCK();
962111297Ssam	}
963104476Ssam}
964104476Ssam
965104476Ssam/*
966104476Ssam * Invoke the callback on behalf of the driver.
967104476Ssam */
968104476Ssamvoid
969104476Ssamcrypto_kdone(struct cryptkop *krp)
970104476Ssam{
971158702Spjd	struct cryptocap *cap;
972104476Ssam
973108587Ssam	if (krp->krp_status != 0)
974108587Ssam		cryptostats.cs_kerrs++;
975158702Spjd	CRYPTO_DRIVER_LOCK();
976158702Spjd	/* XXX: What if driver is loaded in the meantime? */
977158702Spjd	if (krp->krp_hid < crypto_drivers_num) {
978158702Spjd		cap = &crypto_drivers[krp->krp_hid];
979158702Spjd		cap->cc_koperations--;
980158702Spjd		KASSERT(cap->cc_koperations >= 0, ("cc_koperations < 0"));
981158702Spjd		if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
982158702Spjd			crypto_remove(cap);
983158702Spjd	}
984158702Spjd	CRYPTO_DRIVER_UNLOCK();
985104476Ssam	CRYPTO_RETQ_LOCK();
986158702Spjd	if (TAILQ_EMPTY(&crp_ret_kq))
987158702Spjd		wakeup_one(&crp_ret_q);		/* shared wait channel */
988104476Ssam	TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next);
989104628Ssam	CRYPTO_RETQ_UNLOCK();
990104476Ssam}
991104476Ssam
992104476Ssamint
993104476Ssamcrypto_getfeat(int *featp)
994104476Ssam{
995104476Ssam	int hid, kalg, feat = 0;
996104476Ssam
997104476Ssam	if (!crypto_userasymcrypto)
998104476Ssam		goto out;
999104476Ssam
1000104476Ssam	CRYPTO_DRIVER_LOCK();
1001104476Ssam	for (hid = 0; hid < crypto_drivers_num; hid++) {
1002104476Ssam		if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) &&
1003104476Ssam		    !crypto_devallowsoft) {
1004104476Ssam			continue;
1005104476Ssam		}
1006104476Ssam		if (crypto_drivers[hid].cc_kprocess == NULL)
1007104476Ssam			continue;
1008104476Ssam		for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++)
1009104476Ssam			if ((crypto_drivers[hid].cc_kalg[kalg] &
1010104476Ssam			    CRYPTO_ALG_FLAG_SUPPORTED) != 0)
1011104476Ssam				feat |=  1 << kalg;
1012104476Ssam	}
1013104476Ssam	CRYPTO_DRIVER_UNLOCK();
1014104476Ssamout:
1015104476Ssam	*featp = feat;
1016104476Ssam	return (0);
1017104476Ssam}
1018104476Ssam
1019108588Ssam/*
1020108588Ssam * Terminate a thread at module unload.  The process that
1021108588Ssam * initiated this is waiting for us to signal that we're gone;
1022108588Ssam * wake it up and exit.  We use the driver table lock to insure
1023108588Ssam * we don't do the wakeup before they're waiting.  There is no
1024108588Ssam * race here because the waiter sleeps on the proc lock for the
1025108588Ssam * thread so it gets notified at the right time because of an
1026108588Ssam * extra wakeup that's done in exit1().
1027108588Ssam */
1028104476Ssamstatic void
1029108588Ssamcrypto_finis(void *chan)
1030104476Ssam{
1031108588Ssam	CRYPTO_DRIVER_LOCK();
1032108588Ssam	wakeup_one(chan);
1033108588Ssam	CRYPTO_DRIVER_UNLOCK();
1034108588Ssam	kthread_exit(0);
1035104476Ssam}
1036104476Ssam
1037104476Ssam/*
1038104628Ssam * Crypto thread, dispatches crypto requests.
1039104476Ssam */
1040104476Ssamstatic void
1041104476Ssamcrypto_proc(void)
1042104476Ssam{
1043104628Ssam	struct cryptop *crp, *submit;
1044104628Ssam	struct cryptkop *krp;
1045104476Ssam	struct cryptocap *cap;
1046158702Spjd	u_int32_t hid;
1047104476Ssam	int result, hint;
1048104476Ssam
1049104628Ssam	CRYPTO_Q_LOCK();
1050104476Ssam	for (;;) {
1051104476Ssam		/*
1052104476Ssam		 * Find the first element in the queue that can be
1053104476Ssam		 * processed and look-ahead to see if multiple ops
1054104476Ssam		 * are ready for the same driver.
1055104476Ssam		 */
1056104476Ssam		submit = NULL;
1057104476Ssam		hint = 0;
1058104476Ssam		TAILQ_FOREACH(crp, &crp_q, crp_next) {
1059158702Spjd			hid = CRYPTO_SESID2HID(crp->crp_sid);
1060104476Ssam			cap = crypto_checkdriver(hid);
1061158702Spjd			/*
1062158702Spjd			 * Driver cannot disappeared when there is an active
1063158702Spjd			 * session.
1064158702Spjd			 */
1065158716Spjd			KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
1066158716Spjd			    __func__, __LINE__));
1067104476Ssam			if (cap == NULL || cap->cc_process == NULL) {
1068104476Ssam				/* Op needs to be migrated, process it. */
1069104476Ssam				if (submit == NULL)
1070104476Ssam					submit = crp;
1071104476Ssam				break;
1072104476Ssam			}
1073104476Ssam			if (!cap->cc_qblocked) {
1074104476Ssam				if (submit != NULL) {
1075104476Ssam					/*
1076104476Ssam					 * We stop on finding another op,
1077104476Ssam					 * regardless whether its for the same
1078104476Ssam					 * driver or not.  We could keep
1079104476Ssam					 * searching the queue but it might be
1080104476Ssam					 * better to just use a per-driver
1081104476Ssam					 * queue instead.
1082104476Ssam					 */
1083116924Ssam					if (CRYPTO_SESID2HID(submit->crp_sid) == hid)
1084104476Ssam						hint = CRYPTO_HINT_MORE;
1085104476Ssam					break;
1086104476Ssam				} else {
1087104476Ssam					submit = crp;
1088111297Ssam					if ((submit->crp_flags & CRYPTO_F_BATCH) == 0)
1089104476Ssam						break;
1090104476Ssam					/* keep scanning for more are q'd */
1091104476Ssam				}
1092104476Ssam			}
1093104476Ssam		}
1094104476Ssam		if (submit != NULL) {
1095104476Ssam			TAILQ_REMOVE(&crp_q, submit, crp_next);
1096158702Spjd			hid = CRYPTO_SESID2HID(submit->crp_sid);
1097158702Spjd			cap = crypto_checkdriver(hid);
1098158716Spjd			KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
1099158716Spjd			    __func__, __LINE__));
1100158702Spjd			result = crypto_invoke(cap, submit, hint);
1101104476Ssam			if (result == ERESTART) {
1102104476Ssam				/*
1103104476Ssam				 * The driver ran out of resources, mark the
1104104476Ssam				 * driver ``blocked'' for cryptop's and put
1105104476Ssam				 * the request back in the queue.  It would
1106104476Ssam				 * best to put the request back where we got
1107104476Ssam				 * it but that's hard so for now we put it
1108104476Ssam				 * at the front.  This should be ok; putting
1109104476Ssam				 * it at the end does not work.
1110104476Ssam				 */
1111104476Ssam				/* XXX validate sid again? */
1112116924Ssam				crypto_drivers[CRYPTO_SESID2HID(submit->crp_sid)].cc_qblocked = 1;
1113104476Ssam				TAILQ_INSERT_HEAD(&crp_q, submit, crp_next);
1114108587Ssam				cryptostats.cs_blocks++;
1115104476Ssam			}
1116104476Ssam		}
1117104476Ssam
1118104476Ssam		/* As above, but for key ops */
1119104476Ssam		TAILQ_FOREACH(krp, &crp_kq, krp_next) {
1120104476Ssam			cap = crypto_checkdriver(krp->krp_hid);
1121104476Ssam			if (cap == NULL || cap->cc_kprocess == NULL) {
1122104476Ssam				/* Op needs to be migrated, process it. */
1123104476Ssam				break;
1124104476Ssam			}
1125104476Ssam			if (!cap->cc_kqblocked)
1126104476Ssam				break;
1127104476Ssam		}
1128104476Ssam		if (krp != NULL) {
1129104476Ssam			TAILQ_REMOVE(&crp_kq, krp, krp_next);
1130158702Spjd			result = crypto_kinvoke(krp);
1131104476Ssam			if (result == ERESTART) {
1132104476Ssam				/*
1133104476Ssam				 * The driver ran out of resources, mark the
1134104476Ssam				 * driver ``blocked'' for cryptkop'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? */
1142104476Ssam				crypto_drivers[krp->krp_hid].cc_kqblocked = 1;
1143104476Ssam				TAILQ_INSERT_HEAD(&crp_kq, krp, krp_next);
1144108587Ssam				cryptostats.cs_kblocks++;
1145104476Ssam			}
1146104476Ssam		}
1147104476Ssam
1148104628Ssam		if (submit == NULL && krp == NULL) {
1149104476Ssam			/*
1150104476Ssam			 * Nothing more to be processed.  Sleep until we're
1151104476Ssam			 * woken because there are more ops to process.
1152104476Ssam			 * This happens either by submission or by a driver
1153104476Ssam			 * becoming unblocked and notifying us through
1154104476Ssam			 * crypto_unblock.  Note that when we wakeup we
1155104476Ssam			 * start processing each queue again from the
1156104476Ssam			 * front. It's not clear that it's important to
1157104476Ssam			 * preserve this ordering since ops may finish
1158104476Ssam			 * out of order if dispatched to different devices
1159104476Ssam			 * and some become blocked while others do not.
1160104476Ssam			 */
1161104628Ssam			msleep(&crp_q, &crypto_q_mtx, PWAIT, "crypto_wait", 0);
1162108588Ssam			if (cryptoproc == NULL)
1163108588Ssam				break;
1164108587Ssam			cryptostats.cs_intrs++;
1165104476Ssam		}
1166104476Ssam	}
1167108588Ssam	CRYPTO_Q_UNLOCK();
1168104628Ssam
1169108588Ssam	crypto_finis(&crp_q);
1170104628Ssam}
1171104628Ssam
1172104628Ssam/*
1173104628Ssam * Crypto returns thread, does callbacks for processed crypto requests.
1174104628Ssam * Callbacks are done here, rather than in the crypto drivers, because
1175104628Ssam * callbacks typically are expensive and would slow interrupt handling.
1176104628Ssam */
1177104628Ssamstatic void
1178104628Ssamcrypto_ret_proc(void)
1179104628Ssam{
1180104628Ssam	struct cryptop *crpt;
1181104628Ssam	struct cryptkop *krpt;
1182104628Ssam
1183104628Ssam	CRYPTO_RETQ_LOCK();
1184104628Ssam	for (;;) {
1185104628Ssam		/* Harvest return q's for completed ops */
1186104628Ssam		crpt = TAILQ_FIRST(&crp_ret_q);
1187104628Ssam		if (crpt != NULL)
1188104628Ssam			TAILQ_REMOVE(&crp_ret_q, crpt, crp_next);
1189104628Ssam
1190104628Ssam		krpt = TAILQ_FIRST(&crp_ret_kq);
1191104628Ssam		if (krpt != NULL)
1192104628Ssam			TAILQ_REMOVE(&crp_ret_kq, krpt, krp_next);
1193104628Ssam
1194104628Ssam		if (crpt != NULL || krpt != NULL) {
1195104628Ssam			CRYPTO_RETQ_UNLOCK();
1196104628Ssam			/*
1197104628Ssam			 * Run callbacks unlocked.
1198104628Ssam			 */
1199108587Ssam			if (crpt != NULL) {
1200108587Ssam#ifdef CRYPTO_TIMING
1201108587Ssam				if (crypto_timing) {
1202108587Ssam					/*
1203108587Ssam					 * NB: We must copy the timestamp before
1204108587Ssam					 * doing the callback as the cryptop is
1205108587Ssam					 * likely to be reclaimed.
1206108587Ssam					 */
1207108587Ssam					struct bintime t = crpt->crp_tstamp;
1208108587Ssam					crypto_tstat(&cryptostats.cs_cb, &t);
1209108587Ssam					crpt->crp_callback(crpt);
1210108587Ssam					crypto_tstat(&cryptostats.cs_finis, &t);
1211108587Ssam				} else
1212108587Ssam#endif
1213108587Ssam					crpt->crp_callback(crpt);
1214108587Ssam			}
1215104628Ssam			if (krpt != NULL)
1216104628Ssam				krpt->krp_callback(krpt);
1217104628Ssam			CRYPTO_RETQ_LOCK();
1218104628Ssam		} else {
1219104628Ssam			/*
1220104628Ssam			 * Nothing more to be processed.  Sleep until we're
1221104628Ssam			 * woken because there are more returns to process.
1222104628Ssam			 */
1223104628Ssam			msleep(&crp_ret_q, &crypto_ret_q_mtx, PWAIT,
1224104628Ssam				"crypto_ret_wait", 0);
1225108588Ssam			if (cryptoretproc == NULL)
1226108588Ssam				break;
1227108587Ssam			cryptostats.cs_rets++;
1228104628Ssam		}
1229104628Ssam	}
1230108588Ssam	CRYPTO_RETQ_UNLOCK();
1231108588Ssam
1232108588Ssam	crypto_finis(&crp_ret_q);
1233104628Ssam}
1234