xref: /onnv-gate/usr/src/uts/sun4v/io/n2rng/n2rng_kcf.c (revision 5650:7694397e8118)
14625Sgm89044 /*
24625Sgm89044  * CDDL HEADER START
34625Sgm89044  *
44625Sgm89044  * The contents of this file are subject to the terms of the
54625Sgm89044  * Common Development and Distribution License (the "License").
64625Sgm89044  * You may not use this file except in compliance with the License.
74625Sgm89044  *
84625Sgm89044  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94625Sgm89044  * or http://www.opensolaris.org/os/licensing.
104625Sgm89044  * See the License for the specific language governing permissions
114625Sgm89044  * and limitations under the License.
124625Sgm89044  *
134625Sgm89044  * When distributing Covered Code, include this CDDL HEADER in each
144625Sgm89044  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154625Sgm89044  * If applicable, add the following below this CDDL HEADER, with the
164625Sgm89044  * fields enclosed by brackets "[]" replaced with your own identifying
174625Sgm89044  * information: Portions Copyright [yyyy] [name of copyright owner]
184625Sgm89044  *
194625Sgm89044  * CDDL HEADER END
204625Sgm89044  */
214625Sgm89044 /*
224625Sgm89044  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
234625Sgm89044  * Use is subject to license terms.
244625Sgm89044  */
254625Sgm89044 
264625Sgm89044 #pragma ident	"%Z%%M%	%I%	%E% SMI"
274625Sgm89044 
284625Sgm89044 #include <sys/types.h>
294625Sgm89044 #include <sys/uio.h>
304625Sgm89044 #include <sys/stream.h>
314625Sgm89044 #include <sys/ddi.h>
324625Sgm89044 #include <sys/sunddi.h>
334625Sgm89044 #include <sys/strsun.h>
344625Sgm89044 #include <sys/kmem.h>
354625Sgm89044 #include <sys/atomic.h>
364625Sgm89044 #include <sys/random.h>
374625Sgm89044 #include <sys/crypto/common.h>
384625Sgm89044 #include <sys/crypto/spi.h>
394625Sgm89044 #include <sys/n2rng.h>
404625Sgm89044 
414625Sgm89044 #define	IDENT_N2RNG		"SUNW_N2_Random_Number_Generator"
424625Sgm89044 
434625Sgm89044 #define	N2RNG_PROVIDER2N2RNG(x)	(((n2rng_provider_private_t *)x)->mp_n2rng)
444625Sgm89044 
454625Sgm89044 
464625Sgm89044 static void n2rng_provider_status(crypto_provider_handle_t, uint_t *);
474625Sgm89044 
484625Sgm89044 static int n2rng_random_number(crypto_provider_handle_t, crypto_session_id_t,
494625Sgm89044 			uchar_t *, size_t, crypto_req_handle_t);
504625Sgm89044 
514625Sgm89044 static int ext_info(crypto_provider_handle_t, crypto_provider_ext_info_t *,
524625Sgm89044 			crypto_req_handle_t);
534625Sgm89044 
544625Sgm89044 void n2rng_ksinit(n2rng_t *n2rng);
554625Sgm89044 void n2rng_ksdeinit(n2rng_t *n2rng);
564625Sgm89044 
574625Sgm89044 static int fips_init(n2rng_t *n2rng);
584625Sgm89044 static void fips_fini(n2rng_t *n2rng);
594625Sgm89044 int fips_random(n2rng_t *n2rng, uint8_t *out, size_t nbytes);
604625Sgm89044 
614625Sgm89044 
624625Sgm89044 static crypto_control_ops_t n2rng_control_ops = {
634625Sgm89044 	n2rng_provider_status
644625Sgm89044 };
654625Sgm89044 
664625Sgm89044 
674625Sgm89044 static crypto_random_number_ops_t n2rng_rng_ops = {
684625Sgm89044 	NULL,		/* seed_random */
694625Sgm89044 	n2rng_random_number
704625Sgm89044 };
714625Sgm89044 
724625Sgm89044 static crypto_provider_management_ops_t n2rng_extinfo_op = {
734625Sgm89044 	ext_info,	/* ext_info */
744625Sgm89044 	NULL,		/* init_token */
754625Sgm89044 	NULL, 		/* init_pin */
764625Sgm89044 	NULL,		/* set_pin */
774625Sgm89044 };
784625Sgm89044 
794625Sgm89044 static crypto_ops_t n2rng_ops = {
804625Sgm89044 	&n2rng_control_ops,
814625Sgm89044 	NULL,				/* digest_ops */
824625Sgm89044 	NULL,				/* cipher_ops */
834625Sgm89044 	NULL,				/* mac_ops */
844625Sgm89044 	NULL,				/* sign_ops */
854625Sgm89044 	NULL,				/* verify_ops */
864625Sgm89044 	NULL,				/* dual_ops */
874625Sgm89044 	NULL,				/* cipher_mac_ops */
884625Sgm89044 	&n2rng_rng_ops,			/* rng_ops */
894625Sgm89044 	NULL,				/* session_ops */
904625Sgm89044 	NULL,				/* object_ops */
914625Sgm89044 	NULL,				/* key_ops */
924625Sgm89044 	&n2rng_extinfo_op,		/* management_ops */
934625Sgm89044 	NULL,				/* ctx_ops */
944625Sgm89044 	NULL				/* mech_ops */
954625Sgm89044 };
964625Sgm89044 
974625Sgm89044 static crypto_provider_info_t n2rng_prov_info = {
984625Sgm89044 	CRYPTO_SPI_VERSION_2,
994625Sgm89044 	NULL,				/* pi_provider_description */
1004625Sgm89044 	CRYPTO_HW_PROVIDER,
1014625Sgm89044 	NULL,				/* pi_provider_dev */
1024625Sgm89044 	NULL,				/* pi_provider_handle */
1034625Sgm89044 	&n2rng_ops,
1044625Sgm89044 	0,				/* number of mechanisms */
1054625Sgm89044 	NULL,				/* mechanism table */
1064625Sgm89044 	0,				/* pi_logical_provider_count */
1074625Sgm89044 	NULL				/* pi_logical_providers */
1084625Sgm89044 };
1094625Sgm89044 
1104625Sgm89044 static void
strncpy_spacepad(uchar_t * s1,char * s2,int n)1114625Sgm89044 strncpy_spacepad(uchar_t *s1, char *s2, int n)
1124625Sgm89044 {
1134625Sgm89044 	int s2len = strlen(s2);
1144625Sgm89044 
1154625Sgm89044 	(void) strncpy((char *)s1, s2, n);
1164625Sgm89044 	if (s2len < n)
1174625Sgm89044 		(void) memset(s1 + s2len, ' ', n - s2len);
1184625Sgm89044 }
1194625Sgm89044 
1204625Sgm89044 /*ARGSUSED*/
1214625Sgm89044 static int
ext_info(crypto_provider_handle_t prov,crypto_provider_ext_info_t * ext_info,crypto_req_handle_t cfreq)1224625Sgm89044 ext_info(crypto_provider_handle_t prov, crypto_provider_ext_info_t *ext_info,
1234625Sgm89044     crypto_req_handle_t cfreq)
1244625Sgm89044 {
1254625Sgm89044 #define	BUFSZ	64
1264625Sgm89044 	n2rng_t	*n2rng = (n2rng_t *)prov;
1274625Sgm89044 	char	buf[BUFSZ];
1284625Sgm89044 
1294625Sgm89044 	/* handle info common to logical and hardware provider */
1304625Sgm89044 
1314625Sgm89044 	/* Manufacturer ID */
1324625Sgm89044 	strncpy_spacepad(ext_info->ei_manufacturerID, N2RNG_MANUFACTURER_ID,
1334625Sgm89044 	    CRYPTO_EXT_SIZE_MANUF);
1344625Sgm89044 
1354625Sgm89044 	/* Model */
1364625Sgm89044 	strncpy_spacepad(ext_info->ei_model, "0", CRYPTO_EXT_SIZE_MODEL);
1374625Sgm89044 
1384625Sgm89044 	/* Token flags */
1394625Sgm89044 	ext_info->ei_flags = CRYPTO_EXTF_RNG | CRYPTO_EXTF_SO_PIN_LOCKED |
1404625Sgm89044 	    CRYPTO_EXTF_WRITE_PROTECTED;
1414625Sgm89044 
1424625Sgm89044 	ext_info->ei_max_session_count = CRYPTO_EFFECTIVELY_INFINITE;
1434625Sgm89044 	ext_info->ei_max_pin_len = 0;
1444625Sgm89044 	ext_info->ei_min_pin_len = 0;
1454625Sgm89044 	ext_info->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO;
1464625Sgm89044 	ext_info->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO;
1474625Sgm89044 	ext_info->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO;
1484625Sgm89044 	ext_info->ei_free_private_memory = CRYPTO_UNAVAILABLE_INFO;
1494625Sgm89044 
1504625Sgm89044 	/* Time. No need to be supplied for token without a clock */
1514625Sgm89044 	ext_info->ei_time[0] = '\000';
1524625Sgm89044 
1534625Sgm89044 	/* handle hardware provider specific fields */
1544625Sgm89044 
1554625Sgm89044 	/* Token label */
1564625Sgm89044 	(void) snprintf(buf, BUFSZ, "%s/%d SUNW_N2_RNG",
1574625Sgm89044 	    ddi_driver_name(n2rng->n_dip),
1584625Sgm89044 	    ddi_get_instance(n2rng->n_dip));
1594625Sgm89044 
1604625Sgm89044 	/* Serial number */
1614625Sgm89044 	strncpy_spacepad(ext_info->ei_serial_number,
1624625Sgm89044 	    "0",
1634625Sgm89044 	    CRYPTO_EXT_SIZE_SERIAL);
1644625Sgm89044 
1654625Sgm89044 	/* Version info */
1664625Sgm89044 	ext_info->ei_hardware_version.cv_major = 0;
1674625Sgm89044 	ext_info->ei_hardware_version.cv_minor = 0;
1684625Sgm89044 	ext_info->ei_firmware_version.cv_major = 0;
1694625Sgm89044 	ext_info->ei_firmware_version.cv_minor = 0;
1704625Sgm89044 
1714625Sgm89044 	buf[BUFSZ - 1] = '\000';
1724625Sgm89044 	/* set the token label */
1734625Sgm89044 	strncpy_spacepad(ext_info->ei_label, buf, CRYPTO_EXT_SIZE_LABEL);
1744625Sgm89044 
1754625Sgm89044 #undef	BUFSZ
1764625Sgm89044 
1774625Sgm89044 	return (CRYPTO_SUCCESS);
1784625Sgm89044 }
1794625Sgm89044 
180*5650Stwelke static void
unregister_task(void * targ)181*5650Stwelke unregister_task(void *targ)
182*5650Stwelke {
183*5650Stwelke 	n2rng_t *n2rng = (n2rng_t *)targ;
184*5650Stwelke 
185*5650Stwelke 	/* Unregister provider without checking result */
186*5650Stwelke 	(void) n2rng_unregister_provider(n2rng);
187*5650Stwelke }
188*5650Stwelke 
189*5650Stwelke /*
190*5650Stwelke  * Register with KCF if not already registered
191*5650Stwelke  */
192*5650Stwelke int
n2rng_register_provider(n2rng_t * n2rng)193*5650Stwelke n2rng_register_provider(n2rng_t *n2rng)
194*5650Stwelke {
195*5650Stwelke 	int	ret;
196*5650Stwelke 
197*5650Stwelke 	if (n2rng_isregistered(n2rng)) {
198*5650Stwelke 		DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider already "
199*5650Stwelke 		    "registered");
200*5650Stwelke 		return (DDI_SUCCESS);
201*5650Stwelke 	} else {
202*5650Stwelke 		ret = crypto_register_provider(&n2rng_prov_info,
203*5650Stwelke 		    &n2rng->n_prov);
204*5650Stwelke 		if (ret == CRYPTO_SUCCESS) {
205*5650Stwelke 			DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider "
206*5650Stwelke 			    "registered");
207*5650Stwelke 		} else {
208*5650Stwelke 			cmn_err(CE_WARN,
209*5650Stwelke 			    "crypto_register_provider() failed (%d)", ret);
210*5650Stwelke 			n2rng->n_prov = NULL;
211*5650Stwelke 			return (DDI_FAILURE);
212*5650Stwelke 		}
213*5650Stwelke 	}
214*5650Stwelke 	n2rng_setregistered(n2rng);
215*5650Stwelke 	crypto_provider_notification(n2rng->n_prov, CRYPTO_PROVIDER_READY);
216*5650Stwelke 
217*5650Stwelke 	return (DDI_SUCCESS);
218*5650Stwelke }
219*5650Stwelke 
220*5650Stwelke /*
221*5650Stwelke  * Unregister with KCF if not already registered
222*5650Stwelke  */
223*5650Stwelke int
n2rng_unregister_provider(n2rng_t * n2rng)224*5650Stwelke n2rng_unregister_provider(n2rng_t *n2rng)
225*5650Stwelke {
226*5650Stwelke 	if (!n2rng_isregistered(n2rng)) {
227*5650Stwelke 		DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider already "
228*5650Stwelke 		    "unregistered");
229*5650Stwelke 	} else {
230*5650Stwelke 		if (crypto_unregister_provider(n2rng->n_prov) ==
231*5650Stwelke 		    CRYPTO_SUCCESS) {
232*5650Stwelke 			DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider "
233*5650Stwelke 			    "unregistered");
234*5650Stwelke 		} else {
235*5650Stwelke 			n2rng_error(n2rng, "unable to unregister from kcf");
236*5650Stwelke 			return (DDI_FAILURE);
237*5650Stwelke 		}
238*5650Stwelke 	}
239*5650Stwelke 	n2rng->n_prov = NULL;
240*5650Stwelke 	n2rng_clrregistered(n2rng);
241*5650Stwelke 	return (DDI_SUCCESS);
242*5650Stwelke }
243*5650Stwelke 
244*5650Stwelke 
245*5650Stwelke /*
246*5650Stwelke  * Set state to failed for all rngs if in control domain and dispatch a task
247*5650Stwelke  * to unregister from kcf
248*5650Stwelke  */
249*5650Stwelke void
n2rng_failure(n2rng_t * n2rng)250*5650Stwelke n2rng_failure(n2rng_t *n2rng)
251*5650Stwelke {
252*5650Stwelke 	int		rngid;
253*5650Stwelke 	rng_entry_t	*rng;
254*5650Stwelke 
255*5650Stwelke 	mutex_enter(&n2rng->n_lock);
256*5650Stwelke 	/* Check if error has already been detected */
257*5650Stwelke 	if (n2rng_isfailed(n2rng)) {
258*5650Stwelke 		mutex_exit(&n2rng->n_lock);
259*5650Stwelke 		return;
260*5650Stwelke 	}
261*5650Stwelke 
262*5650Stwelke 	cmn_err(CE_WARN, "n2rng: hardware failure detected");
263*5650Stwelke 	n2rng_setfailed(n2rng);
264*5650Stwelke 
265*5650Stwelke 	/* Set each rng to failed if running in control domain */
266*5650Stwelke 	if (n2rng_iscontrol(n2rng)) {
267*5650Stwelke 		for (rngid = 0; rngid < n2rng->n_ctl_data->n_num_rngs;
268*5650Stwelke 		    rngid++) {
269*5650Stwelke 			rng = &n2rng->n_ctl_data->n_rngs[rngid];
270*5650Stwelke 			rng->n_rng_state = CTL_STATE_ERROR;
271*5650Stwelke 		}
272*5650Stwelke 	}
273*5650Stwelke 	mutex_exit(&n2rng->n_lock);
274*5650Stwelke 
275*5650Stwelke 	/* Dispatch task to unregister from kcf */
276*5650Stwelke 	if (ddi_taskq_dispatch(n2rng->n_taskq, unregister_task,
277*5650Stwelke 	    (void *)n2rng, DDI_SLEEP) !=  DDI_SUCCESS) {
278*5650Stwelke 		cmn_err(CE_WARN, "n2rng: ddi_taskq_dispatch() failed");
279*5650Stwelke 	}
280*5650Stwelke }
281*5650Stwelke 
282*5650Stwelke /*
283*5650Stwelke  * Set state to unconfigured for all rngs if in control domain and dispatch a
284*5650Stwelke  * task to unregister from kcf.
285*5650Stwelke  */
286*5650Stwelke void
n2rng_unconfigured(n2rng_t * n2rng)287*5650Stwelke n2rng_unconfigured(n2rng_t *n2rng)
288*5650Stwelke {
289*5650Stwelke 	int		rngid;
290*5650Stwelke 	rng_entry_t	*rng;
291*5650Stwelke 
292*5650Stwelke 	mutex_enter(&n2rng->n_lock);
293*5650Stwelke 	/* Check if unconfigured state has already been detected */
294*5650Stwelke 	if (!n2rng_isconfigured(n2rng)) {
295*5650Stwelke 		mutex_exit(&n2rng->n_lock);
296*5650Stwelke 		return;
297*5650Stwelke 	}
298*5650Stwelke 
299*5650Stwelke 	cmn_err(CE_WARN, "n2rng: no longer generating entropy");
300*5650Stwelke 	n2rng_clrconfigured(n2rng);
301*5650Stwelke 
302*5650Stwelke 	/* Set each rng to unconfigured if running in control domain */
303*5650Stwelke 	if (n2rng_iscontrol(n2rng)) {
304*5650Stwelke 		for (rngid = 0; rngid < n2rng->n_ctl_data->n_num_rngs;
305*5650Stwelke 		    rngid++) {
306*5650Stwelke 			rng = &n2rng->n_ctl_data->n_rngs[rngid];
307*5650Stwelke 			rng->n_rng_state = CTL_STATE_UNCONFIGURED;
308*5650Stwelke 		}
309*5650Stwelke 	}
310*5650Stwelke 	mutex_exit(&n2rng->n_lock);
311*5650Stwelke 
312*5650Stwelke 	/* Dispatch task to unregister from kcf */
313*5650Stwelke 	if (ddi_taskq_dispatch(n2rng->n_taskq, unregister_task,
314*5650Stwelke 	    (void *)n2rng, DDI_SLEEP) !=  DDI_SUCCESS) {
315*5650Stwelke 		cmn_err(CE_WARN, "n2rng: ddi_taskq_dispatch() failed");
316*5650Stwelke 	} else {
317*5650Stwelke 		/* Schedule a configuration retry */
318*5650Stwelke 		n2rng_config_retry(n2rng, RNG_CFG_RETRY_SECS);
319*5650Stwelke 	}
320*5650Stwelke }
3214625Sgm89044 
3224625Sgm89044 /*
3234625Sgm89044  * Setup and also register to kCF
3244625Sgm89044  */
3254625Sgm89044 int
n2rng_init(n2rng_t * n2rng)3264625Sgm89044 n2rng_init(n2rng_t *n2rng)
3274625Sgm89044 {
3284625Sgm89044 	int		ret;
3294625Sgm89044 	char		ID[64];
3304625Sgm89044 	dev_info_t	*dip;
3314625Sgm89044 
3324625Sgm89044 	dip = n2rng->n_dip;
3334625Sgm89044 
334*5650Stwelke 	/* Initialize data structures if not already done */
335*5650Stwelke 	if (!n2rng_isinitialized(n2rng)) {
336*5650Stwelke 		/* initialize kstats */
337*5650Stwelke 		n2rng_ksinit(n2rng);
3384625Sgm89044 
339*5650Stwelke 		/* initialize the FIPS data and mutexes */
340*5650Stwelke 		ret = fips_init(n2rng);
341*5650Stwelke 		if (ret) {
342*5650Stwelke 			n2rng_ksdeinit(n2rng);
343*5650Stwelke 			return (DDI_FAILURE);
344*5650Stwelke 		}
3454625Sgm89044 	}
3464625Sgm89044 
347*5650Stwelke 	/*
348*5650Stwelke 	 * Register with crypto framework if not already registered.
349*5650Stwelke 	 * Be careful not to exceed 32 characters.
350*5650Stwelke 	 */
3514625Sgm89044 	(void) sprintf(ID, "%s/%d %s",
3524625Sgm89044 	    ddi_driver_name(dip), ddi_get_instance(dip),
3534625Sgm89044 	    IDENT_N2RNG);
3544625Sgm89044 	n2rng_prov_info.pi_provider_description = ID;
3554625Sgm89044 	n2rng_prov_info.pi_provider_dev.pd_hw = dip;
3564625Sgm89044 	n2rng_prov_info.pi_provider_handle = n2rng;
357*5650Stwelke 	n2rng_setinitialized(n2rng);
358*5650Stwelke 	ret = n2rng_register_provider(n2rng);
359*5650Stwelke 	if (ret != DDI_SUCCESS) {
3604625Sgm89044 		fips_fini(n2rng);
3614625Sgm89044 		n2rng_ksdeinit(n2rng);
362*5650Stwelke 		n2rng_clrinitialized(n2rng);
3634625Sgm89044 		return (DDI_FAILURE);
3644625Sgm89044 	}
3654625Sgm89044 
3664625Sgm89044 	return (DDI_SUCCESS);
3674625Sgm89044 }
3684625Sgm89044 
3694625Sgm89044 /*
3704625Sgm89044  * Unregister from kCF and cleanup
3714625Sgm89044  */
3724625Sgm89044 int
n2rng_uninit(n2rng_t * n2rng)3734625Sgm89044 n2rng_uninit(n2rng_t *n2rng)
3744625Sgm89044 {
375*5650Stwelke 	/* Un-initialize data structures if they exist */
376*5650Stwelke 	if (n2rng_isinitialized(n2rng)) {
377*5650Stwelke 		/*
378*5650Stwelke 		 * Unregister from kCF.
379*5650Stwelke 		 * This needs to be done at the beginning of detach.
380*5650Stwelke 		 */
381*5650Stwelke 		if (n2rng_unregister_provider(n2rng) != DDI_SUCCESS) {
3824625Sgm89044 			return (DDI_FAILURE);
3834625Sgm89044 		}
384*5650Stwelke 
385*5650Stwelke 		fips_fini(n2rng);
3864625Sgm89044 
387*5650Stwelke 		/* deinitialize kstats */
388*5650Stwelke 		n2rng_ksdeinit(n2rng);
389*5650Stwelke 		n2rng_clrinitialized(n2rng);
390*5650Stwelke 	}
3914625Sgm89044 
3924625Sgm89044 	return (DDI_SUCCESS);
3934625Sgm89044 }
3944625Sgm89044 
3954625Sgm89044 /*
3964625Sgm89044  * At this time there are no periodic health checks.  If the health
3974625Sgm89044  * check done at attrach time fails, the driver does not even attach.
3984625Sgm89044  * So there are no failure conditions to report, and this provider is
3994625Sgm89044  * never busy.
4004625Sgm89044  */
4014625Sgm89044 /* ARGSUSED */
4024625Sgm89044 static void
n2rng_provider_status(crypto_provider_handle_t provider,uint_t * status)4034625Sgm89044 n2rng_provider_status(crypto_provider_handle_t provider, uint_t *status)
4044625Sgm89044 {
4054625Sgm89044 	*status = CRYPTO_PROVIDER_READY;
4064625Sgm89044 }
4074625Sgm89044 
4084625Sgm89044 /*ARGSUSED*/
4094625Sgm89044 static int
n2rng_random_number(crypto_provider_handle_t provider,crypto_session_id_t sess,unsigned char * buf,size_t buflen,crypto_req_handle_t cfreq)4104625Sgm89044 n2rng_random_number(crypto_provider_handle_t provider,
4114625Sgm89044 	crypto_session_id_t sess, unsigned char *buf, size_t buflen,
4124625Sgm89044 	crypto_req_handle_t cfreq)
4134625Sgm89044 {
4144625Sgm89044 	n2rng_t		*n2rng = (n2rng_t *)provider;
4154625Sgm89044 	int		rv;
4164625Sgm89044 
4174625Sgm89044 	rv = fips_random(n2rng, buf, buflen);
4184625Sgm89044 
4194625Sgm89044 	atomic_add_64(&n2rng->n_stats[DS_RNGBYTES], buflen);
4204625Sgm89044 	atomic_inc_64(&n2rng->n_stats[DS_RNGJOBS]);
4214625Sgm89044 
4224625Sgm89044 	return (rv);
4234625Sgm89044 }
4244625Sgm89044 
4254625Sgm89044 static int
fips_init(n2rng_t * n2rng)4264625Sgm89044 fips_init(n2rng_t *n2rng)
4274625Sgm89044 {
4284625Sgm89044 	int		i;
4294625Sgm89044 	int		rv;
4304625Sgm89044 
4314625Sgm89044 	n2rng->n_frs.fips_round_robin_j = 0;
4324625Sgm89044 	for (i = 0; i < N2RNG_FIPS_INSTANCES; i++) {
4334625Sgm89044 		rv = n2rng_fips_random_init(n2rng, &n2rng->n_frs.fipsarray[i]);
4344625Sgm89044 		if (rv) {
4354625Sgm89044 			/* finalize all the FIPS structures allocated so far */
4364625Sgm89044 			for (--i; i >= 0; --i) {
4374625Sgm89044 				n2rng_fips_random_fini(
4384625Sgm89044 				    &n2rng->n_frs.fipsarray[i]);
4394625Sgm89044 			}
4404625Sgm89044 			return (rv);
4414625Sgm89044 		}
4424625Sgm89044 	}
4434625Sgm89044 	return (0);
4444625Sgm89044 }
4454625Sgm89044 
4464625Sgm89044 static void
fips_fini(n2rng_t * n2rng)4474625Sgm89044 fips_fini(n2rng_t *n2rng)
4484625Sgm89044 {
4494625Sgm89044 	int		i;
4504625Sgm89044 
4514625Sgm89044 	for (i = 0; i < N2RNG_FIPS_INSTANCES; i++) {
4524625Sgm89044 		n2rng_fips_random_fini(&n2rng->n_frs.fipsarray[i]);
4534625Sgm89044 	}
4544625Sgm89044 }
455