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