xref: /openbsd-src/sys/crypto/crypto.c (revision 87edded1683044e3d2775bb27ee8e9db185147d3)
1*87edded1Stobhe /*	$OpenBSD: crypto.c,v 1.92 2021/10/24 14:50:42 tobhe Exp $	*/
27a398ca3Sangelos /*
37a398ca3Sangelos  * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
47a398ca3Sangelos  *
57a398ca3Sangelos  * This code was written by Angelos D. Keromytis in Athens, Greece, in
67a398ca3Sangelos  * February 2000. Network Security Technologies Inc. (NSTI) kindly
77a398ca3Sangelos  * supported the development of this code.
87a398ca3Sangelos  *
99d566f6dSangelos  * Copyright (c) 2000, 2001 Angelos D. Keromytis
107a398ca3Sangelos  *
119d566f6dSangelos  * Permission to use, copy, and modify this software with or without fee
127a398ca3Sangelos  * is hereby granted, provided that this entire notice is included in
137a398ca3Sangelos  * all source code copies of any software which is or includes a copy or
147a398ca3Sangelos  * modification of this software.
157a398ca3Sangelos  *
167a398ca3Sangelos  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
177a398ca3Sangelos  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
187a398ca3Sangelos  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
197a398ca3Sangelos  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
207a398ca3Sangelos  * PURPOSE.
217a398ca3Sangelos  */
227a398ca3Sangelos 
237a398ca3Sangelos #include <sys/param.h>
247a398ca3Sangelos #include <sys/systm.h>
257a398ca3Sangelos #include <sys/malloc.h>
26f2bfb140Sangelos #include <sys/pool.h>
273802724fStedu 
2882eb8fdeSderaadt #include <crypto/cryptodev.h>
297a398ca3Sangelos 
307a02b0b9Sbluhm /*
317a02b0b9Sbluhm  * Locks used to protect struct members in this file:
327a02b0b9Sbluhm  *	A	allocated during driver attach, no hotplug, no detach
337a02b0b9Sbluhm  *	I	immutable after creation
347a02b0b9Sbluhm  *	K	kernel lock
357a02b0b9Sbluhm  */
363802724fStedu 
377a02b0b9Sbluhm struct cryptocap *crypto_drivers;	/* [A] array allocated by driver
387a02b0b9Sbluhm 					   [K] driver data and session count */
397a02b0b9Sbluhm int crypto_drivers_num = 0;		/* [A] attached drivers array size */
407a398ca3Sangelos 
417a02b0b9Sbluhm struct pool cryptop_pool;		/* [I] set of crypto descriptors */
427a398ca3Sangelos 
437a398ca3Sangelos /*
447a398ca3Sangelos  * Create a new session.
457a398ca3Sangelos  */
467a398ca3Sangelos int
crypto_newsession(u_int64_t * sid,struct cryptoini * cri,int hard)474385f535Sderaadt crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard)
487a398ca3Sangelos {
49fc652f68Sjason 	u_int32_t hid, lid, hid2 = -1;
50fc652f68Sjason 	struct cryptocap *cpc;
517a398ca3Sangelos 	struct cryptoini *cr;
52fc652f68Sjason 	int err, s, turn = 0;
537a398ca3Sangelos 
547a398ca3Sangelos 	if (crypto_drivers == NULL)
557a398ca3Sangelos 		return EINVAL;
567a398ca3Sangelos 
577a02b0b9Sbluhm 	KERNEL_ASSERT_LOCKED();
587a02b0b9Sbluhm 
59a6aba590Sthib 	s = splvm();
60a6aba590Sthib 
617a398ca3Sangelos 	/*
627a398ca3Sangelos 	 * The algorithm we use here is pretty stupid; just use the
63fc652f68Sjason 	 * first driver that supports all the algorithms we need. Do
64fc652f68Sjason 	 * a double-pass over all the drivers, ignoring software ones
65fc652f68Sjason 	 * at first, to deal with cases of drivers that register after
66fc652f68Sjason 	 * the software one(s) --- e.g., PCMCIA crypto cards.
677a398ca3Sangelos 	 *
687a398ca3Sangelos 	 * XXX We need more smarts here (in real life too, but that's
697a398ca3Sangelos 	 * XXX another story altogether).
707a398ca3Sangelos 	 */
71fc652f68Sjason 	do {
72f98f91e9Sart 		for (hid = 0; hid < crypto_drivers_num; hid++) {
73fc652f68Sjason 			cpc = &crypto_drivers[hid];
74fc652f68Sjason 
757a398ca3Sangelos 			/*
76f9de3e10Sangelos 			 * If it's not initialized or has remaining sessions
77f9de3e10Sangelos 			 * referencing it, skip.
787a398ca3Sangelos 			 */
79fc652f68Sjason 			if (cpc->cc_newsession == NULL ||
80fc652f68Sjason 			    (cpc->cc_flags & CRYPTOCAP_F_CLEANUP))
817a398ca3Sangelos 				continue;
827a398ca3Sangelos 
83fc652f68Sjason 			if (cpc->cc_flags & CRYPTOCAP_F_SOFTWARE) {
84fc652f68Sjason 				/*
85fc652f68Sjason 				 * First round of search, ignore
86fc652f68Sjason 				 * software drivers.
87fc652f68Sjason 				 */
88fc652f68Sjason 				if (turn == 0)
894385f535Sderaadt 					continue;
90fc652f68Sjason 			} else { /* !CRYPTOCAP_F_SOFTWARE */
91fc652f68Sjason 				/* Second round of search, only software. */
92fc652f68Sjason 				if (turn == 1)
93fc652f68Sjason 					continue;
94fc652f68Sjason 			}
954385f535Sderaadt 
96f9de3e10Sangelos 			/* See if all the algorithms are supported. */
97fc652f68Sjason 			for (cr = cri; cr; cr = cr->cri_next) {
98fc652f68Sjason 				if (cpc->cc_alg[cr->cri_alg] == 0)
997a398ca3Sangelos 					break;
1007a398ca3Sangelos 			}
1017a398ca3Sangelos 
1027a398ca3Sangelos 			/*
103fc652f68Sjason 			 * If even one algorithm is not supported,
104fc652f68Sjason 			 * keep searching.
105fc652f68Sjason 			 */
106fc652f68Sjason 			if (cr != NULL)
107fc652f68Sjason 				continue;
108fc652f68Sjason 
109fc652f68Sjason 			/*
110fc652f68Sjason 			 * If we had a previous match, see how it compares
111fc652f68Sjason 			 * to this one. Keep "remembering" whichever is
112fc652f68Sjason 			 * the best of the two.
113fc652f68Sjason 			 */
114fc652f68Sjason 			if (hid2 != -1) {
115fc652f68Sjason 				/*
116fc652f68Sjason 				 * Compare session numbers, pick the one
117fc652f68Sjason 				 * with the lowest.
118fc652f68Sjason 				 * XXX Need better metrics, this will
119fc652f68Sjason 				 * XXX just do un-weighted round-robin.
120fc652f68Sjason 				 */
121fc652f68Sjason 				if (crypto_drivers[hid].cc_sessions <=
122fc652f68Sjason 				    crypto_drivers[hid2].cc_sessions)
123fc652f68Sjason 					hid2 = hid;
124fc652f68Sjason 			} else {
125fc652f68Sjason 				/*
126fc652f68Sjason 				 * Remember this one, for future
127fc652f68Sjason                                  * comparisons.
128fc652f68Sjason 				 */
129fc652f68Sjason 				hid2 = hid;
130fc652f68Sjason 			}
131fc652f68Sjason 		}
132fc652f68Sjason 
133fc652f68Sjason 		/*
134fc652f68Sjason 		 * If we found something worth remembering, leave. The
135fc652f68Sjason 		 * side-effect is that we will always prefer a hardware
136fc652f68Sjason 		 * driver over the software one.
137fc652f68Sjason 		 */
138fc652f68Sjason 		if (hid2 != -1)
139fc652f68Sjason 			break;
140fc652f68Sjason 
141fc652f68Sjason 		turn++;
142fc652f68Sjason 
143fc652f68Sjason 		/* If we only want hardware drivers, don't do second pass. */
144fc652f68Sjason 	} while (turn <= 2 && hard == 0);
145fc652f68Sjason 
146fc652f68Sjason 	hid = hid2;
147fc652f68Sjason 
148fc652f68Sjason 	/*
1497a398ca3Sangelos 	 * Can't do everything in one session.
1507a398ca3Sangelos 	 *
151fc652f68Sjason 	 * XXX Fix this. We need to inject a "virtual" session
152fc652f68Sjason 	 * XXX layer right about here.
1537a398ca3Sangelos 	 */
1547a398ca3Sangelos 
155a6aba590Sthib 	if (hid == -1) {
156a6aba590Sthib 		splx(s);
1577a398ca3Sangelos 		return EINVAL;
158a6aba590Sthib 	}
1597a398ca3Sangelos 
160f9de3e10Sangelos 	/* Call the driver initialization routine. */
161f9de3e10Sangelos 	lid = hid; /* Pass the driver ID. */
1627a398ca3Sangelos 	err = crypto_drivers[hid].cc_newsession(&lid, cri);
1638a4e6689Sderaadt 	if (err == 0) {
1647a398ca3Sangelos 		(*sid) = hid;
1654e76590cSprovos 		(*sid) <<= 32;
1667a398ca3Sangelos 		(*sid) |= (lid & 0xffffffff);
1677a398ca3Sangelos 		crypto_drivers[hid].cc_sessions++;
1687a398ca3Sangelos 	}
1697a398ca3Sangelos 
170f2bfb140Sangelos 	splx(s);
1717a398ca3Sangelos 	return err;
1727a398ca3Sangelos }
1737a398ca3Sangelos 
1747a398ca3Sangelos /*
1757a398ca3Sangelos  * Delete an existing session (or a reserved session on an unregistered
1767a398ca3Sangelos  * driver).
1777a398ca3Sangelos  */
1787a398ca3Sangelos int
crypto_freesession(u_int64_t sid)1797a398ca3Sangelos crypto_freesession(u_int64_t sid)
1807a398ca3Sangelos {
181f2bfb140Sangelos 	int err = 0, s;
182bcf5c14bSangelos 	u_int32_t hid;
1837a398ca3Sangelos 
1847a398ca3Sangelos 	if (crypto_drivers == NULL)
1857a398ca3Sangelos 		return EINVAL;
1867a398ca3Sangelos 
187f9de3e10Sangelos 	/* Determine two IDs. */
1884e76590cSprovos 	hid = (sid >> 32) & 0xffffffff;
1897a398ca3Sangelos 
1907a398ca3Sangelos 	if (hid >= crypto_drivers_num)
1917a398ca3Sangelos 		return ENOENT;
1927a398ca3Sangelos 
1937a02b0b9Sbluhm 	KERNEL_ASSERT_LOCKED();
1947a02b0b9Sbluhm 
195232d301dSbrad 	s = splvm();
196f2bfb140Sangelos 
1977a398ca3Sangelos 	if (crypto_drivers[hid].cc_sessions)
1987a398ca3Sangelos 		crypto_drivers[hid].cc_sessions--;
1997a398ca3Sangelos 
200f9de3e10Sangelos 	/* Call the driver cleanup routine, if available. */
2017a398ca3Sangelos 	if (crypto_drivers[hid].cc_freesession)
202bcf5c14bSangelos 		err = crypto_drivers[hid].cc_freesession(sid);
2037a398ca3Sangelos 
2047a398ca3Sangelos 	/*
2058a4e6689Sderaadt 	 * If this was the last session of a driver marked as invalid,
2068a4e6689Sderaadt 	 * make the entry available for reuse.
2077a398ca3Sangelos 	 */
2087a398ca3Sangelos 	if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) &&
2098a4e6689Sderaadt 	    crypto_drivers[hid].cc_sessions == 0)
210fa2d22afSderaadt 		explicit_bzero(&crypto_drivers[hid], sizeof(struct cryptocap));
2117a398ca3Sangelos 
212f2bfb140Sangelos 	splx(s);
2137a398ca3Sangelos 	return err;
2147a398ca3Sangelos }
2157a398ca3Sangelos 
2167a398ca3Sangelos /*
2177a398ca3Sangelos  * Find an empty slot.
2187a398ca3Sangelos  */
2197a398ca3Sangelos int32_t
crypto_get_driverid(u_int8_t flags)220460f87bbSderaadt crypto_get_driverid(u_int8_t flags)
2217a398ca3Sangelos {
2227a398ca3Sangelos 	struct cryptocap *newdrv;
2235eb891adStedu 	int i, s;
2245eb891adStedu 
2257a02b0b9Sbluhm 	/* called from attach routines */
2267a02b0b9Sbluhm 	KERNEL_ASSERT_LOCKED();
2277a02b0b9Sbluhm 
2285eb891adStedu 	s = splvm();
2297a398ca3Sangelos 
2308a4e6689Sderaadt 	if (crypto_drivers_num == 0) {
2317a398ca3Sangelos 		crypto_drivers_num = CRYPTO_DRIVERS_INITIAL;
232a973d15aSderaadt 		crypto_drivers = mallocarray(crypto_drivers_num,
233156a7e2bSdlg 		    sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT | M_ZERO);
2348a4e6689Sderaadt 		if (crypto_drivers == NULL) {
2357a398ca3Sangelos 			crypto_drivers_num = 0;
2365eb891adStedu 			splx(s);
2377a398ca3Sangelos 			return -1;
2387a398ca3Sangelos 		}
2397a398ca3Sangelos 	}
2407a398ca3Sangelos 
2418a4e6689Sderaadt 	for (i = 0; i < crypto_drivers_num; i++) {
2428a4e6689Sderaadt 		if (crypto_drivers[i].cc_process == NULL &&
2437a398ca3Sangelos 		    !(crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) &&
2448a4e6689Sderaadt 		    crypto_drivers[i].cc_sessions == 0) {
245f2bfb140Sangelos 			crypto_drivers[i].cc_sessions = 1; /* Mark */
24654b9f4c9Sderaadt 			crypto_drivers[i].cc_flags = flags;
247f2bfb140Sangelos 			splx(s);
2487a398ca3Sangelos 			return i;
249f2bfb140Sangelos 		}
2508a4e6689Sderaadt 	}
2517a398ca3Sangelos 
252f9de3e10Sangelos 	/* Out of entries, allocate some more. */
253f35a2544Stedu 	if (crypto_drivers_num >= CRYPTO_DRIVERS_MAX) {
254f2bfb140Sangelos 		splx(s);
2557a398ca3Sangelos 		return -1;
256f2bfb140Sangelos 	}
2577a398ca3Sangelos 
258a973d15aSderaadt 	newdrv = mallocarray(crypto_drivers_num,
259a973d15aSderaadt 	    2 * sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT);
2608a4e6689Sderaadt 	if (newdrv == NULL) {
261f2bfb140Sangelos 		splx(s);
2627a398ca3Sangelos 		return -1;
263f2bfb140Sangelos 	}
2647a398ca3Sangelos 
2654e5722bbStedu 	memcpy(newdrv, crypto_drivers,
2667a398ca3Sangelos 	    crypto_drivers_num * sizeof(struct cryptocap));
2677a398ca3Sangelos 	bzero(&newdrv[crypto_drivers_num],
2687a398ca3Sangelos 	    crypto_drivers_num * sizeof(struct cryptocap));
269f2bfb140Sangelos 
270f2bfb140Sangelos 	newdrv[i].cc_sessions = 1; /* Mark */
271460f87bbSderaadt 	newdrv[i].cc_flags = flags;
272f2bfb140Sangelos 
273bae2bd50Sderaadt 	free(crypto_drivers, M_CRYPTO_DATA,
274bae2bd50Sderaadt 	    crypto_drivers_num * sizeof(struct cryptocap));
275bae2bd50Sderaadt 
276bae2bd50Sderaadt 	crypto_drivers_num *= 2;
277f2bfb140Sangelos 	crypto_drivers = newdrv;
278f2bfb140Sangelos 	splx(s);
2797a398ca3Sangelos 	return i;
2807a398ca3Sangelos }
2817a398ca3Sangelos 
2827a398ca3Sangelos /*
2837a398ca3Sangelos  * Register a crypto driver. It should be called once for each algorithm
2847a398ca3Sangelos  * supported by the driver.
2857a398ca3Sangelos  */
2867a398ca3Sangelos int
crypto_register(u_int32_t driverid,int * alg,int (* newses)(u_int32_t *,struct cryptoini *),int (* freeses)(u_int64_t),int (* process)(struct cryptop *))287fc652f68Sjason crypto_register(u_int32_t driverid, int *alg,
288cc47f85cSderaadt     int (*newses)(u_int32_t *, struct cryptoini *),
289cc47f85cSderaadt     int (*freeses)(u_int64_t), int (*process)(struct cryptop *))
2907a398ca3Sangelos {
291fc652f68Sjason 	int s, i;
292f2bfb140Sangelos 
293fc652f68Sjason 	if (driverid >= crypto_drivers_num || alg == NULL ||
294fc652f68Sjason 	    crypto_drivers == NULL)
2957a398ca3Sangelos 		return EINVAL;
2967a398ca3Sangelos 
2977a02b0b9Sbluhm 	/* called from attach routines */
2987a02b0b9Sbluhm 	KERNEL_ASSERT_LOCKED();
2997a02b0b9Sbluhm 
300232d301dSbrad 	s = splvm();
301f2bfb140Sangelos 
30297c531daSthib 	for (i = 0; i <= CRYPTO_ALGORITHM_MAX; i++) {
3037a398ca3Sangelos 		/*
304fc652f68Sjason 		 * XXX Do some performance testing to determine
305fc652f68Sjason 		 * placing.  We probably need an auxiliary data
306fc652f68Sjason 		 * structure that describes relative performances.
3077a398ca3Sangelos 		 */
3087a398ca3Sangelos 
309fc652f68Sjason 		crypto_drivers[driverid].cc_alg[i] = alg[i];
310fc652f68Sjason 	}
31118e9ec63Sangelos 
3127a398ca3Sangelos 
313cc47f85cSderaadt 	crypto_drivers[driverid].cc_newsession = newses;
314cc47f85cSderaadt 	crypto_drivers[driverid].cc_process = process;
315cc47f85cSderaadt 	crypto_drivers[driverid].cc_freesession = freeses;
316f2bfb140Sangelos 	crypto_drivers[driverid].cc_sessions = 0; /* Unmark */
3177a398ca3Sangelos 
318f2bfb140Sangelos 	splx(s);
319fc652f68Sjason 
3207a398ca3Sangelos 	return 0;
3217a398ca3Sangelos }
3227a398ca3Sangelos 
3237a398ca3Sangelos /*
3247a398ca3Sangelos  * Unregister a crypto driver. If there are pending sessions using it,
3257a398ca3Sangelos  * leave enough information around so that subsequent calls using those
3267a398ca3Sangelos  * sessions will correctly detect the driver being unregistered and reroute
3277a398ca3Sangelos  * the request.
3287a398ca3Sangelos  */
3297a398ca3Sangelos int
crypto_unregister(u_int32_t driverid,int alg)3307a398ca3Sangelos crypto_unregister(u_int32_t driverid, int alg)
3317a398ca3Sangelos {
3325eb891adStedu 	int i = CRYPTO_ALGORITHM_MAX + 1, s;
3337a398ca3Sangelos 	u_int32_t ses;
3347a398ca3Sangelos 
3357a02b0b9Sbluhm 	/* may be called from detach routines, but not used */
3367a02b0b9Sbluhm 	KERNEL_ASSERT_LOCKED();
3377a02b0b9Sbluhm 
3385eb891adStedu 	s = splvm();
3395eb891adStedu 
340fc652f68Sjason 	/* Sanity checks. */
341fc652f68Sjason 	if (driverid >= crypto_drivers_num || crypto_drivers == NULL ||
342cbf8475bSkrw 	    alg <= 0 || alg > (CRYPTO_ALGORITHM_MAX + 1)) {
343f2bfb140Sangelos 		splx(s);
3447a398ca3Sangelos 		return EINVAL;
345f2bfb140Sangelos 	}
3467a398ca3Sangelos 
34797c531daSthib 	if (alg != CRYPTO_ALGORITHM_MAX + 1) {
348cbf8475bSkrw 		if (crypto_drivers[driverid].cc_alg[alg] == 0) {
349cbf8475bSkrw 			splx(s);
350cbf8475bSkrw 			return EINVAL;
351cbf8475bSkrw 		}
3527a398ca3Sangelos 		crypto_drivers[driverid].cc_alg[alg] = 0;
3537a398ca3Sangelos 
3547a398ca3Sangelos 		/* Was this the last algorithm ? */
3557a398ca3Sangelos 		for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
3567a398ca3Sangelos 			if (crypto_drivers[driverid].cc_alg[i] != 0)
3577a398ca3Sangelos 				break;
358fc652f68Sjason 	}
3597a398ca3Sangelos 
360fc652f68Sjason 	/*
361fc652f68Sjason 	 * If a driver unregistered its last algorithm or all of them
36297c531daSthib 	 * (alg == CRYPTO_ALGORITHM_MAX + 1), cleanup its entry.
363fc652f68Sjason 	 */
36497c531daSthib 	if (i == CRYPTO_ALGORITHM_MAX + 1 || alg == CRYPTO_ALGORITHM_MAX + 1) {
3657a398ca3Sangelos 		ses = crypto_drivers[driverid].cc_sessions;
3667a398ca3Sangelos 		bzero(&crypto_drivers[driverid], sizeof(struct cryptocap));
3678a4e6689Sderaadt 		if (ses != 0) {
368f9de3e10Sangelos 			/*
369f9de3e10Sangelos 			 * If there are pending sessions, just mark as invalid.
370f9de3e10Sangelos 			 */
3717a398ca3Sangelos 			crypto_drivers[driverid].cc_flags |= CRYPTOCAP_F_CLEANUP;
3727a398ca3Sangelos 			crypto_drivers[driverid].cc_sessions = ses;
3737a398ca3Sangelos 		}
3747a398ca3Sangelos 	}
375f2bfb140Sangelos 	splx(s);
3767a398ca3Sangelos 	return 0;
3777a398ca3Sangelos }
3787a398ca3Sangelos 
3797a398ca3Sangelos /*
3808a16a66fSangelos  * Dispatch a crypto request to the appropriate crypto devices.
3818a16a66fSangelos  */
382*87edded1Stobhe int
crypto_invoke(struct cryptop * crp)3838a16a66fSangelos crypto_invoke(struct cryptop *crp)
3848a16a66fSangelos {
3857a398ca3Sangelos 	u_int64_t nid;
3867a398ca3Sangelos 	u_int32_t hid;
387999ac441Sderaadt 	int error;
388e410e70dSpatrick 	int s, i;
3897a398ca3Sangelos 
390f9de3e10Sangelos 	/* Sanity checks. */
3913877526aSbluhm 	KASSERT(crp != NULL);
3927a398ca3Sangelos 
3930ae95220Sbluhm 	KERNEL_ASSERT_LOCKED();
3940ae95220Sbluhm 
3957cb5f37fStedu 	s = splvm();
396e410e70dSpatrick 	if (crp->crp_ndesc < 1 || crypto_drivers == NULL) {
397*87edded1Stobhe 		error = EINVAL;
3983877526aSbluhm 		goto done;
3997a398ca3Sangelos 	}
4007a398ca3Sangelos 
4014e76590cSprovos 	hid = (crp->crp_sid >> 32) & 0xffffffff;
402fc652f68Sjason 	if (hid >= crypto_drivers_num)
403fc652f68Sjason 		goto migrate;
404795ccb2bSangelos 
405fc652f68Sjason 	if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) {
406f98f91e9Sart 		crypto_freesession(crp->crp_sid);
407fc652f68Sjason 		goto migrate;
408f98f91e9Sart 	}
409f98f91e9Sart 
410fc652f68Sjason 	if (crypto_drivers[hid].cc_process == NULL)
411fc652f68Sjason 		goto migrate;
412fc652f68Sjason 
413fc652f68Sjason 	crypto_drivers[hid].cc_operations++;
414fc652f68Sjason 	crypto_drivers[hid].cc_bytes += crp->crp_ilen;
415fc652f68Sjason 
416f98f91e9Sart 	error = crypto_drivers[hid].cc_process(crp);
417fc652f68Sjason 	if (error == ERESTART) {
418fc652f68Sjason 		/* Unregister driver and migrate session. */
41997c531daSthib 		crypto_unregister(hid, CRYPTO_ALGORITHM_MAX + 1);
420fc652f68Sjason 		goto migrate;
421fc652f68Sjason 	}
422fc652f68Sjason 
4237cb5f37fStedu 	splx(s);
424*87edded1Stobhe 	return error;
425fc652f68Sjason 
426fc652f68Sjason  migrate:
427fc652f68Sjason 	/* Migrate session. */
428e410e70dSpatrick 	for (i = 0; i < crp->crp_ndesc - 1; i++)
429e410e70dSpatrick 		crp->crp_desc[i].CRD_INI.cri_next = &crp->crp_desc[i+1].CRD_INI;
430e410e70dSpatrick 	crp->crp_desc[crp->crp_ndesc].CRD_INI.cri_next = NULL;
431fc652f68Sjason 
432fc652f68Sjason 	if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0)
433fc652f68Sjason 		crp->crp_sid = nid;
434fc652f68Sjason 
435*87edded1Stobhe 	error = EAGAIN;
4363877526aSbluhm  done:
4377cb5f37fStedu 	splx(s);
438*87edded1Stobhe 	return error;
439f98f91e9Sart }
440f98f91e9Sart 
4417a398ca3Sangelos /*
4427a398ca3Sangelos  * Release a set of crypto descriptors.
4437a398ca3Sangelos  */
4447a398ca3Sangelos void
crypto_freereq(struct cryptop * crp)4457a398ca3Sangelos crypto_freereq(struct cryptop *crp)
4467a398ca3Sangelos {
4477a398ca3Sangelos 	if (crp == NULL)
4487a398ca3Sangelos 		return;
4497a398ca3Sangelos 
450e410e70dSpatrick 	if (crp->crp_ndescalloc > 2)
451e410e70dSpatrick 		free(crp->crp_desc, M_CRYPTO_DATA,
452e410e70dSpatrick 		    crp->crp_ndescalloc * sizeof(struct cryptodesc));
453f2bfb140Sangelos 	pool_put(&cryptop_pool, crp);
4547a398ca3Sangelos }
4557a398ca3Sangelos 
4567a398ca3Sangelos /*
4577a398ca3Sangelos  * Acquire a set of crypto descriptors.
4587a398ca3Sangelos  */
4597a398ca3Sangelos struct cryptop *
crypto_getreq(int num)4607a398ca3Sangelos crypto_getreq(int num)
4617a398ca3Sangelos {
4627a398ca3Sangelos 	struct cryptop *crp;
4637a398ca3Sangelos 
464156a7e2bSdlg 	crp = pool_get(&cryptop_pool, PR_NOWAIT | PR_ZERO);
465011f9670Sdlg 	if (crp == NULL)
4667a398ca3Sangelos 		return NULL;
4677a398ca3Sangelos 
468e410e70dSpatrick 	crp->crp_desc = crp->crp_sdesc;
469e410e70dSpatrick 	crp->crp_ndescalloc = crp->crp_ndesc = num;
470e410e70dSpatrick 
471e410e70dSpatrick 	if (num > 2) {
472e410e70dSpatrick 		crp->crp_desc = mallocarray(num, sizeof(struct cryptodesc),
473e410e70dSpatrick 		    M_CRYPTO_DATA, M_NOWAIT | M_ZERO);
474e410e70dSpatrick 		if (crp->crp_desc == NULL) {
475e410e70dSpatrick 			pool_put(&cryptop_pool, crp);
4767a398ca3Sangelos 			return NULL;
4777a398ca3Sangelos 		}
4787a398ca3Sangelos 	}
4797a398ca3Sangelos 
4807a398ca3Sangelos 	return crp;
4817a398ca3Sangelos }
4828a16a66fSangelos 
4838a16a66fSangelos void
crypto_init(void)484160898eaSjsing crypto_init(void)
4858a16a66fSangelos {
4861378bae2Sdlg 	pool_init(&cryptop_pool, sizeof(struct cryptop), 0, IPL_VM, 0,
4871378bae2Sdlg 	    "cryptop", NULL);
4888a16a66fSangelos }
489