xref: /illumos-gate/usr/src/uts/sun4v/io/n2rng/n2rng_kcf.c (revision 03b8b03e)
1fec509a0Sgm /*
2fec509a0Sgm  * CDDL HEADER START
3fec509a0Sgm  *
4fec509a0Sgm  * The contents of this file are subject to the terms of the
5fec509a0Sgm  * Common Development and Distribution License (the "License").
6fec509a0Sgm  * You may not use this file except in compliance with the License.
7fec509a0Sgm  *
8fec509a0Sgm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fec509a0Sgm  * or http://www.opensolaris.org/os/licensing.
10fec509a0Sgm  * See the License for the specific language governing permissions
11fec509a0Sgm  * and limitations under the License.
12fec509a0Sgm  *
13fec509a0Sgm  * When distributing Covered Code, include this CDDL HEADER in each
14fec509a0Sgm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fec509a0Sgm  * If applicable, add the following below this CDDL HEADER, with the
16fec509a0Sgm  * fields enclosed by brackets "[]" replaced with your own identifying
17fec509a0Sgm  * information: Portions Copyright [yyyy] [name of copyright owner]
18fec509a0Sgm  *
19fec509a0Sgm  * CDDL HEADER END
20fec509a0Sgm  */
21fec509a0Sgm /*
22fec509a0Sgm  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23fec509a0Sgm  * Use is subject to license terms.
24fec509a0Sgm  */
25fec509a0Sgm 
26fec509a0Sgm #include <sys/types.h>
27fec509a0Sgm #include <sys/uio.h>
28fec509a0Sgm #include <sys/stream.h>
29fec509a0Sgm #include <sys/ddi.h>
30fec509a0Sgm #include <sys/sunddi.h>
31fec509a0Sgm #include <sys/strsun.h>
32fec509a0Sgm #include <sys/kmem.h>
33fec509a0Sgm #include <sys/atomic.h>
34fec509a0Sgm #include <sys/random.h>
35fec509a0Sgm #include <sys/crypto/common.h>
36fec509a0Sgm #include <sys/crypto/spi.h>
37fec509a0Sgm #include <sys/n2rng.h>
38fec509a0Sgm 
39fec509a0Sgm #define	IDENT_N2RNG		"SUNW_N2_Random_Number_Generator"
40fec509a0Sgm 
41fec509a0Sgm #define	N2RNG_PROVIDER2N2RNG(x)	(((n2rng_provider_private_t *)x)->mp_n2rng)
42fec509a0Sgm 
43fec509a0Sgm 
44fec509a0Sgm static void n2rng_provider_status(crypto_provider_handle_t, uint_t *);
45fec509a0Sgm 
46fec509a0Sgm static int n2rng_random_number(crypto_provider_handle_t, crypto_session_id_t,
47fec509a0Sgm 			uchar_t *, size_t, crypto_req_handle_t);
48fec509a0Sgm 
49fec509a0Sgm static int ext_info(crypto_provider_handle_t, crypto_provider_ext_info_t *,
50fec509a0Sgm 			crypto_req_handle_t);
51fec509a0Sgm 
52fec509a0Sgm void n2rng_ksinit(n2rng_t *n2rng);
53fec509a0Sgm void n2rng_ksdeinit(n2rng_t *n2rng);
54fec509a0Sgm 
55fec509a0Sgm static int fips_init(n2rng_t *n2rng);
56fec509a0Sgm static void fips_fini(n2rng_t *n2rng);
57fec509a0Sgm int fips_random(n2rng_t *n2rng, uint8_t *out, size_t nbytes);
58fec509a0Sgm 
59fec509a0Sgm 
60fec509a0Sgm static crypto_control_ops_t n2rng_control_ops = {
61fec509a0Sgm 	n2rng_provider_status
62fec509a0Sgm };
63fec509a0Sgm 
64fec509a0Sgm 
65fec509a0Sgm static crypto_random_number_ops_t n2rng_rng_ops = {
66fec509a0Sgm 	NULL,		/* seed_random */
67fec509a0Sgm 	n2rng_random_number
68fec509a0Sgm };
69fec509a0Sgm 
70fec509a0Sgm static crypto_provider_management_ops_t n2rng_extinfo_op = {
71fec509a0Sgm 	ext_info,	/* ext_info */
72fec509a0Sgm 	NULL,		/* init_token */
73*03b8b03eSToomas Soome 	NULL,		/* init_pin */
74fec509a0Sgm 	NULL,		/* set_pin */
75fec509a0Sgm };
76fec509a0Sgm 
77fec509a0Sgm static crypto_ops_t n2rng_ops = {
78fec509a0Sgm 	&n2rng_control_ops,
79fec509a0Sgm 	NULL,				/* digest_ops */
80fec509a0Sgm 	NULL,				/* cipher_ops */
81fec509a0Sgm 	NULL,				/* mac_ops */
82fec509a0Sgm 	NULL,				/* sign_ops */
83fec509a0Sgm 	NULL,				/* verify_ops */
84fec509a0Sgm 	NULL,				/* dual_ops */
85fec509a0Sgm 	NULL,				/* cipher_mac_ops */
86fec509a0Sgm 	&n2rng_rng_ops,			/* rng_ops */
87fec509a0Sgm 	NULL,				/* session_ops */
88fec509a0Sgm 	NULL,				/* object_ops */
89fec509a0Sgm 	NULL,				/* key_ops */
90fec509a0Sgm 	&n2rng_extinfo_op,		/* management_ops */
91fec509a0Sgm 	NULL,				/* ctx_ops */
92fec509a0Sgm 	NULL				/* mech_ops */
93fec509a0Sgm };
94fec509a0Sgm 
95fec509a0Sgm static crypto_provider_info_t n2rng_prov_info = {
96fec509a0Sgm 	CRYPTO_SPI_VERSION_2,
97fec509a0Sgm 	NULL,				/* pi_provider_description */
98fec509a0Sgm 	CRYPTO_HW_PROVIDER,
99fec509a0Sgm 	NULL,				/* pi_provider_dev */
100fec509a0Sgm 	NULL,				/* pi_provider_handle */
101fec509a0Sgm 	&n2rng_ops,
102fec509a0Sgm 	0,				/* number of mechanisms */
103fec509a0Sgm 	NULL,				/* mechanism table */
104fec509a0Sgm 	0,				/* pi_logical_provider_count */
105fec509a0Sgm 	NULL				/* pi_logical_providers */
106fec509a0Sgm };
107fec509a0Sgm 
108fec509a0Sgm static void
strncpy_spacepad(uchar_t * s1,char * s2,int n)109fec509a0Sgm strncpy_spacepad(uchar_t *s1, char *s2, int n)
110fec509a0Sgm {
111fec509a0Sgm 	int s2len = strlen(s2);
112fec509a0Sgm 
113fec509a0Sgm 	(void) strncpy((char *)s1, s2, n);
114fec509a0Sgm 	if (s2len < n)
115fec509a0Sgm 		(void) memset(s1 + s2len, ' ', n - s2len);
116fec509a0Sgm }
117fec509a0Sgm 
118fec509a0Sgm /*ARGSUSED*/
119fec509a0Sgm static int
ext_info(crypto_provider_handle_t prov,crypto_provider_ext_info_t * ext_info,crypto_req_handle_t cfreq)120fec509a0Sgm ext_info(crypto_provider_handle_t prov, crypto_provider_ext_info_t *ext_info,
121fec509a0Sgm     crypto_req_handle_t cfreq)
122fec509a0Sgm {
123fec509a0Sgm #define	BUFSZ	64
124fec509a0Sgm 	n2rng_t	*n2rng = (n2rng_t *)prov;
125fec509a0Sgm 	char	buf[BUFSZ];
126fec509a0Sgm 
127fec509a0Sgm 	/* handle info common to logical and hardware provider */
128fec509a0Sgm 
129fec509a0Sgm 	/* Manufacturer ID */
130fec509a0Sgm 	strncpy_spacepad(ext_info->ei_manufacturerID, N2RNG_MANUFACTURER_ID,
131fec509a0Sgm 	    CRYPTO_EXT_SIZE_MANUF);
132fec509a0Sgm 
133fec509a0Sgm 	/* Model */
134fec509a0Sgm 	strncpy_spacepad(ext_info->ei_model, "0", CRYPTO_EXT_SIZE_MODEL);
135fec509a0Sgm 
136fec509a0Sgm 	/* Token flags */
137fec509a0Sgm 	ext_info->ei_flags = CRYPTO_EXTF_RNG | CRYPTO_EXTF_SO_PIN_LOCKED |
138fec509a0Sgm 	    CRYPTO_EXTF_WRITE_PROTECTED;
139fec509a0Sgm 
140fec509a0Sgm 	ext_info->ei_max_session_count = CRYPTO_EFFECTIVELY_INFINITE;
141fec509a0Sgm 	ext_info->ei_max_pin_len = 0;
142fec509a0Sgm 	ext_info->ei_min_pin_len = 0;
143fec509a0Sgm 	ext_info->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO;
144fec509a0Sgm 	ext_info->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO;
145fec509a0Sgm 	ext_info->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO;
146fec509a0Sgm 	ext_info->ei_free_private_memory = CRYPTO_UNAVAILABLE_INFO;
147fec509a0Sgm 
148fec509a0Sgm 	/* Time. No need to be supplied for token without a clock */
149fec509a0Sgm 	ext_info->ei_time[0] = '\000';
150fec509a0Sgm 
151fec509a0Sgm 	/* handle hardware provider specific fields */
152fec509a0Sgm 
153fec509a0Sgm 	/* Token label */
154fec509a0Sgm 	(void) snprintf(buf, BUFSZ, "%s/%d SUNW_N2_RNG",
155fec509a0Sgm 	    ddi_driver_name(n2rng->n_dip),
156fec509a0Sgm 	    ddi_get_instance(n2rng->n_dip));
157fec509a0Sgm 
158fec509a0Sgm 	/* Serial number */
159fec509a0Sgm 	strncpy_spacepad(ext_info->ei_serial_number,
160fec509a0Sgm 	    "0",
161fec509a0Sgm 	    CRYPTO_EXT_SIZE_SERIAL);
162fec509a0Sgm 
163fec509a0Sgm 	/* Version info */
164fec509a0Sgm 	ext_info->ei_hardware_version.cv_major = 0;
165fec509a0Sgm 	ext_info->ei_hardware_version.cv_minor = 0;
166fec509a0Sgm 	ext_info->ei_firmware_version.cv_major = 0;
167fec509a0Sgm 	ext_info->ei_firmware_version.cv_minor = 0;
168fec509a0Sgm 
169fec509a0Sgm 	buf[BUFSZ - 1] = '\000';
170fec509a0Sgm 	/* set the token label */
171fec509a0Sgm 	strncpy_spacepad(ext_info->ei_label, buf, CRYPTO_EXT_SIZE_LABEL);
172fec509a0Sgm 
173fec509a0Sgm #undef	BUFSZ
174fec509a0Sgm 
175fec509a0Sgm 	return (CRYPTO_SUCCESS);
176fec509a0Sgm }
177fec509a0Sgm 
178741c280dStwelke static void
unregister_task(void * targ)179741c280dStwelke unregister_task(void *targ)
180741c280dStwelke {
181741c280dStwelke 	n2rng_t *n2rng = (n2rng_t *)targ;
182741c280dStwelke 
183741c280dStwelke 	/* Unregister provider without checking result */
184741c280dStwelke 	(void) n2rng_unregister_provider(n2rng);
185741c280dStwelke }
186741c280dStwelke 
187741c280dStwelke /*
188741c280dStwelke  * Register with KCF if not already registered
189741c280dStwelke  */
190741c280dStwelke int
n2rng_register_provider(n2rng_t * n2rng)191741c280dStwelke n2rng_register_provider(n2rng_t *n2rng)
192741c280dStwelke {
193741c280dStwelke 	int	ret;
194741c280dStwelke 
195741c280dStwelke 	if (n2rng_isregistered(n2rng)) {
196741c280dStwelke 		DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider already "
197741c280dStwelke 		    "registered");
198741c280dStwelke 		return (DDI_SUCCESS);
199741c280dStwelke 	} else {
200741c280dStwelke 		ret = crypto_register_provider(&n2rng_prov_info,
201741c280dStwelke 		    &n2rng->n_prov);
202741c280dStwelke 		if (ret == CRYPTO_SUCCESS) {
203741c280dStwelke 			DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider "
204741c280dStwelke 			    "registered");
205741c280dStwelke 		} else {
206741c280dStwelke 			cmn_err(CE_WARN,
207741c280dStwelke 			    "crypto_register_provider() failed (%d)", ret);
208*03b8b03eSToomas Soome 			n2rng->n_prov = 0;
209741c280dStwelke 			return (DDI_FAILURE);
210741c280dStwelke 		}
211741c280dStwelke 	}
212741c280dStwelke 	n2rng_setregistered(n2rng);
213741c280dStwelke 	crypto_provider_notification(n2rng->n_prov, CRYPTO_PROVIDER_READY);
214741c280dStwelke 
215741c280dStwelke 	return (DDI_SUCCESS);
216741c280dStwelke }
217741c280dStwelke 
218741c280dStwelke /*
219741c280dStwelke  * Unregister with KCF if not already registered
220741c280dStwelke  */
221741c280dStwelke int
n2rng_unregister_provider(n2rng_t * n2rng)222741c280dStwelke n2rng_unregister_provider(n2rng_t *n2rng)
223741c280dStwelke {
224741c280dStwelke 	if (!n2rng_isregistered(n2rng)) {
225741c280dStwelke 		DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider already "
226741c280dStwelke 		    "unregistered");
227741c280dStwelke 	} else {
228741c280dStwelke 		if (crypto_unregister_provider(n2rng->n_prov) ==
229741c280dStwelke 		    CRYPTO_SUCCESS) {
230741c280dStwelke 			DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider "
231741c280dStwelke 			    "unregistered");
232741c280dStwelke 		} else {
233741c280dStwelke 			n2rng_error(n2rng, "unable to unregister from kcf");
234741c280dStwelke 			return (DDI_FAILURE);
235741c280dStwelke 		}
236741c280dStwelke 	}
237*03b8b03eSToomas Soome 	n2rng->n_prov = 0;
238741c280dStwelke 	n2rng_clrregistered(n2rng);
239741c280dStwelke 	return (DDI_SUCCESS);
240741c280dStwelke }
241741c280dStwelke 
242741c280dStwelke 
243741c280dStwelke /*
244741c280dStwelke  * Set state to failed for all rngs if in control domain and dispatch a task
245741c280dStwelke  * to unregister from kcf
246741c280dStwelke  */
247741c280dStwelke void
n2rng_failure(n2rng_t * n2rng)248741c280dStwelke n2rng_failure(n2rng_t *n2rng)
249741c280dStwelke {
250741c280dStwelke 	int		rngid;
251741c280dStwelke 	rng_entry_t	*rng;
252741c280dStwelke 
253741c280dStwelke 	mutex_enter(&n2rng->n_lock);
254741c280dStwelke 	/* Check if error has already been detected */
255741c280dStwelke 	if (n2rng_isfailed(n2rng)) {
256741c280dStwelke 		mutex_exit(&n2rng->n_lock);
257741c280dStwelke 		return;
258741c280dStwelke 	}
259741c280dStwelke 
260741c280dStwelke 	cmn_err(CE_WARN, "n2rng: hardware failure detected");
261741c280dStwelke 	n2rng_setfailed(n2rng);
262741c280dStwelke 
263741c280dStwelke 	/* Set each rng to failed if running in control domain */
264741c280dStwelke 	if (n2rng_iscontrol(n2rng)) {
265741c280dStwelke 		for (rngid = 0; rngid < n2rng->n_ctl_data->n_num_rngs;
266741c280dStwelke 		    rngid++) {
267741c280dStwelke 			rng = &n2rng->n_ctl_data->n_rngs[rngid];
268741c280dStwelke 			rng->n_rng_state = CTL_STATE_ERROR;
269741c280dStwelke 		}
270741c280dStwelke 	}
271741c280dStwelke 	mutex_exit(&n2rng->n_lock);
272741c280dStwelke 
273741c280dStwelke 	/* Dispatch task to unregister from kcf */
274741c280dStwelke 	if (ddi_taskq_dispatch(n2rng->n_taskq, unregister_task,
275741c280dStwelke 	    (void *)n2rng, DDI_SLEEP) !=  DDI_SUCCESS) {
276741c280dStwelke 		cmn_err(CE_WARN, "n2rng: ddi_taskq_dispatch() failed");
277741c280dStwelke 	}
278741c280dStwelke }
279741c280dStwelke 
280741c280dStwelke /*
281741c280dStwelke  * Set state to unconfigured for all rngs if in control domain and dispatch a
282741c280dStwelke  * task to unregister from kcf.
283741c280dStwelke  */
284741c280dStwelke void
n2rng_unconfigured(n2rng_t * n2rng)285741c280dStwelke n2rng_unconfigured(n2rng_t *n2rng)
286741c280dStwelke {
287741c280dStwelke 	int		rngid;
288741c280dStwelke 	rng_entry_t	*rng;
289741c280dStwelke 
290741c280dStwelke 	mutex_enter(&n2rng->n_lock);
291741c280dStwelke 	/* Check if unconfigured state has already been detected */
292741c280dStwelke 	if (!n2rng_isconfigured(n2rng)) {
293741c280dStwelke 		mutex_exit(&n2rng->n_lock);
294741c280dStwelke 		return;
295741c280dStwelke 	}
296741c280dStwelke 
297741c280dStwelke 	cmn_err(CE_WARN, "n2rng: no longer generating entropy");
298741c280dStwelke 	n2rng_clrconfigured(n2rng);
299741c280dStwelke 
300741c280dStwelke 	/* Set each rng to unconfigured if running in control domain */
301741c280dStwelke 	if (n2rng_iscontrol(n2rng)) {
302741c280dStwelke 		for (rngid = 0; rngid < n2rng->n_ctl_data->n_num_rngs;
303741c280dStwelke 		    rngid++) {
304741c280dStwelke 			rng = &n2rng->n_ctl_data->n_rngs[rngid];
305741c280dStwelke 			rng->n_rng_state = CTL_STATE_UNCONFIGURED;
306741c280dStwelke 		}
307741c280dStwelke 	}
308741c280dStwelke 	mutex_exit(&n2rng->n_lock);
309741c280dStwelke 
310741c280dStwelke 	/* Dispatch task to unregister from kcf */
311741c280dStwelke 	if (ddi_taskq_dispatch(n2rng->n_taskq, unregister_task,
312741c280dStwelke 	    (void *)n2rng, DDI_SLEEP) !=  DDI_SUCCESS) {
313741c280dStwelke 		cmn_err(CE_WARN, "n2rng: ddi_taskq_dispatch() failed");
314741c280dStwelke 	} else {
315741c280dStwelke 		/* Schedule a configuration retry */
316741c280dStwelke 		n2rng_config_retry(n2rng, RNG_CFG_RETRY_SECS);
317741c280dStwelke 	}
318741c280dStwelke }
319fec509a0Sgm 
320fec509a0Sgm /*
321fec509a0Sgm  * Setup and also register to kCF
322fec509a0Sgm  */
323fec509a0Sgm int
n2rng_init(n2rng_t * n2rng)324fec509a0Sgm n2rng_init(n2rng_t *n2rng)
325fec509a0Sgm {
326fec509a0Sgm 	int		ret;
327fec509a0Sgm 	char		ID[64];
328fec509a0Sgm 	dev_info_t	*dip;
329fec509a0Sgm 
330fec509a0Sgm 	dip = n2rng->n_dip;
331fec509a0Sgm 
332741c280dStwelke 	/* Initialize data structures if not already done */
333741c280dStwelke 	if (!n2rng_isinitialized(n2rng)) {
334741c280dStwelke 		/* initialize kstats */
335741c280dStwelke 		n2rng_ksinit(n2rng);
336fec509a0Sgm 
337741c280dStwelke 		/* initialize the FIPS data and mutexes */
338741c280dStwelke 		ret = fips_init(n2rng);
339741c280dStwelke 		if (ret) {
340741c280dStwelke 			n2rng_ksdeinit(n2rng);
341741c280dStwelke 			return (DDI_FAILURE);
342741c280dStwelke 		}
343fec509a0Sgm 	}
344fec509a0Sgm 
345741c280dStwelke 	/*
346741c280dStwelke 	 * Register with crypto framework if not already registered.
347741c280dStwelke 	 * Be careful not to exceed 32 characters.
348741c280dStwelke 	 */
349fec509a0Sgm 	(void) sprintf(ID, "%s/%d %s",
350fec509a0Sgm 	    ddi_driver_name(dip), ddi_get_instance(dip),
351fec509a0Sgm 	    IDENT_N2RNG);
352fec509a0Sgm 	n2rng_prov_info.pi_provider_description = ID;
353fec509a0Sgm 	n2rng_prov_info.pi_provider_dev.pd_hw = dip;
354fec509a0Sgm 	n2rng_prov_info.pi_provider_handle = n2rng;
355741c280dStwelke 	n2rng_setinitialized(n2rng);
356741c280dStwelke 	ret = n2rng_register_provider(n2rng);
357741c280dStwelke 	if (ret != DDI_SUCCESS) {
358fec509a0Sgm 		fips_fini(n2rng);
359fec509a0Sgm 		n2rng_ksdeinit(n2rng);
360741c280dStwelke 		n2rng_clrinitialized(n2rng);
361fec509a0Sgm 		return (DDI_FAILURE);
362fec509a0Sgm 	}
363fec509a0Sgm 
364fec509a0Sgm 	return (DDI_SUCCESS);
365fec509a0Sgm }
366fec509a0Sgm 
367fec509a0Sgm /*
368fec509a0Sgm  * Unregister from kCF and cleanup
369fec509a0Sgm  */
370fec509a0Sgm int
n2rng_uninit(n2rng_t * n2rng)371fec509a0Sgm n2rng_uninit(n2rng_t *n2rng)
372fec509a0Sgm {
373741c280dStwelke 	/* Un-initialize data structures if they exist */
374741c280dStwelke 	if (n2rng_isinitialized(n2rng)) {
375741c280dStwelke 		/*
376741c280dStwelke 		 * Unregister from kCF.
377741c280dStwelke 		 * This needs to be done at the beginning of detach.
378741c280dStwelke 		 */
379741c280dStwelke 		if (n2rng_unregister_provider(n2rng) != DDI_SUCCESS) {
380fec509a0Sgm 			return (DDI_FAILURE);
381fec509a0Sgm 		}
382fec509a0Sgm 
383741c280dStwelke 		fips_fini(n2rng);
384fec509a0Sgm 
385741c280dStwelke 		/* deinitialize kstats */
386741c280dStwelke 		n2rng_ksdeinit(n2rng);
387741c280dStwelke 		n2rng_clrinitialized(n2rng);
388741c280dStwelke 	}
389fec509a0Sgm 
390fec509a0Sgm 	return (DDI_SUCCESS);
391fec509a0Sgm }
392fec509a0Sgm 
393fec509a0Sgm /*
394fec509a0Sgm  * At this time there are no periodic health checks.  If the health
395fec509a0Sgm  * check done at attrach time fails, the driver does not even attach.
396fec509a0Sgm  * So there are no failure conditions to report, and this provider is
397fec509a0Sgm  * never busy.
398fec509a0Sgm  */
399fec509a0Sgm /* ARGSUSED */
400fec509a0Sgm static void
n2rng_provider_status(crypto_provider_handle_t provider,uint_t * status)401fec509a0Sgm n2rng_provider_status(crypto_provider_handle_t provider, uint_t *status)
402fec509a0Sgm {
403fec509a0Sgm 	*status = CRYPTO_PROVIDER_READY;
404fec509a0Sgm }
405fec509a0Sgm 
406fec509a0Sgm /*ARGSUSED*/
407fec509a0Sgm 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)408fec509a0Sgm n2rng_random_number(crypto_provider_handle_t provider,
409*03b8b03eSToomas Soome     crypto_session_id_t sess, unsigned char *buf, size_t buflen,
410*03b8b03eSToomas Soome     crypto_req_handle_t cfreq)
411fec509a0Sgm {
412fec509a0Sgm 	n2rng_t		*n2rng = (n2rng_t *)provider;
413fec509a0Sgm 	int		rv;
414fec509a0Sgm 
415fec509a0Sgm 	rv = fips_random(n2rng, buf, buflen);
416fec509a0Sgm 
417fec509a0Sgm 	atomic_add_64(&n2rng->n_stats[DS_RNGBYTES], buflen);
418fec509a0Sgm 	atomic_inc_64(&n2rng->n_stats[DS_RNGJOBS]);
419fec509a0Sgm 
420fec509a0Sgm 	return (rv);
421fec509a0Sgm }
422fec509a0Sgm 
423fec509a0Sgm static int
fips_init(n2rng_t * n2rng)424fec509a0Sgm fips_init(n2rng_t *n2rng)
425fec509a0Sgm {
426fec509a0Sgm 	int		i;
427fec509a0Sgm 	int		rv;
428fec509a0Sgm 
429fec509a0Sgm 	n2rng->n_frs.fips_round_robin_j = 0;
430fec509a0Sgm 	for (i = 0; i < N2RNG_FIPS_INSTANCES; i++) {
431fec509a0Sgm 		rv = n2rng_fips_random_init(n2rng, &n2rng->n_frs.fipsarray[i]);
432fec509a0Sgm 		if (rv) {
433fec509a0Sgm 			/* finalize all the FIPS structures allocated so far */
434fec509a0Sgm 			for (--i; i >= 0; --i) {
435fec509a0Sgm 				n2rng_fips_random_fini(
436fec509a0Sgm 				    &n2rng->n_frs.fipsarray[i]);
437fec509a0Sgm 			}
438fec509a0Sgm 			return (rv);
439fec509a0Sgm 		}
440fec509a0Sgm 	}
441fec509a0Sgm 	return (0);
442fec509a0Sgm }
443fec509a0Sgm 
444fec509a0Sgm static void
fips_fini(n2rng_t * n2rng)445fec509a0Sgm fips_fini(n2rng_t *n2rng)
446fec509a0Sgm {
447fec509a0Sgm 	int		i;
448fec509a0Sgm 
449fec509a0Sgm 	for (i = 0; i < N2RNG_FIPS_INSTANCES; i++) {
450fec509a0Sgm 		n2rng_fips_random_fini(&n2rng->n_frs.fipsarray[i]);
451fec509a0Sgm 	}
452fec509a0Sgm }
453