xref: /freebsd/sys/dev/random/randomdev.c (revision d1b06863fbc7b142d7afdf2d399087e2fab40f16)
14db9ae91SMark Murray /*-
2*d1b06863SMark Murray  * Copyright (c) 2000-2015 Mark R V Murray
34db9ae91SMark Murray  * All rights reserved.
44db9ae91SMark Murray  *
54db9ae91SMark Murray  * Redistribution and use in source and binary forms, with or without
64db9ae91SMark Murray  * modification, are permitted provided that the following conditions
74db9ae91SMark Murray  * are met:
84db9ae91SMark Murray  * 1. Redistributions of source code must retain the above copyright
94db9ae91SMark Murray  *    notice, this list of conditions and the following disclaimer
104db9ae91SMark Murray  *    in this position and unchanged.
114db9ae91SMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
124db9ae91SMark Murray  *    notice, this list of conditions and the following disclaimer in the
134db9ae91SMark Murray  *    documentation and/or other materials provided with the distribution.
144db9ae91SMark Murray  *
154db9ae91SMark Murray  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
164db9ae91SMark Murray  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
174db9ae91SMark Murray  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
184db9ae91SMark Murray  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
194db9ae91SMark Murray  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
204db9ae91SMark Murray  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
214db9ae91SMark Murray  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
224db9ae91SMark Murray  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
234db9ae91SMark Murray  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
244db9ae91SMark Murray  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
254db9ae91SMark Murray  *
264db9ae91SMark Murray  */
274db9ae91SMark Murray 
28aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
29aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
30aad970f1SDavid E. O'Brien 
314db9ae91SMark Murray #include <sys/param.h>
324db9ae91SMark Murray #include <sys/systm.h>
33fb919e4dSMark Murray #include <sys/bus.h>
344db9ae91SMark Murray #include <sys/conf.h>
354db9ae91SMark Murray #include <sys/fcntl.h>
36fb919e4dSMark Murray #include <sys/filio.h>
374db9ae91SMark Murray #include <sys/kernel.h>
3802c986abSMark Murray #include <sys/kthread.h>
39fb919e4dSMark Murray #include <sys/lock.h>
4041ee9f1cSPoul-Henning Kamp #include <sys/module.h>
4110cb2424SMark Murray #include <sys/malloc.h>
42*d1b06863SMark Murray #include <sys/poll.h>
43b40ce416SJulian Elischer #include <sys/proc.h>
44f02e47dcSMark Murray #include <sys/random.h>
45*d1b06863SMark Murray #include <sys/sbuf.h>
46*d1b06863SMark Murray #include <sys/selinfo.h>
4710cb2424SMark Murray #include <sys/sysctl.h>
4810cb2424SMark Murray #include <sys/systm.h>
49fb919e4dSMark Murray #include <sys/uio.h>
5002c986abSMark Murray #include <sys/unistd.h>
514db9ae91SMark Murray 
52*d1b06863SMark Murray #include <crypto/rijndael/rijndael-api-fst.h>
53*d1b06863SMark Murray #include <crypto/sha2/sha2.h>
54*d1b06863SMark Murray 
55*d1b06863SMark Murray #include <dev/random/hash.h>
5602c986abSMark Murray #include <dev/random/randomdev.h>
57095ed2c9SMark Murray #include <dev/random/random_harvestq.h>
584db9ae91SMark Murray 
59*d1b06863SMark Murray #include "opt_random.h"
60*d1b06863SMark Murray 
61*d1b06863SMark Murray #if defined(RANDOM_DUMMY) && defined(RANDOM_YARROW)
62*d1b06863SMark Murray #error "Cannot define both RANDOM_DUMMY and RANDOM_YARROW"
63*d1b06863SMark Murray #endif
64*d1b06863SMark Murray 
65e7806b4cSMark Murray #define	RANDOM_MINOR	0
66e7806b4cSMark Murray 
67*d1b06863SMark Murray static d_read_t randomdev_read;
68*d1b06863SMark Murray static d_write_t randomdev_write;
69*d1b06863SMark Murray static d_poll_t randomdev_poll;
7010cb2424SMark Murray static d_ioctl_t randomdev_ioctl;
714db9ae91SMark Murray 
724db9ae91SMark Murray static struct cdevsw random_cdevsw = {
737ac40f5fSPoul-Henning Kamp 	.d_name = "random",
7410cb2424SMark Murray 	.d_version = D_VERSION,
75*d1b06863SMark Murray 	.d_read = randomdev_read,
76*d1b06863SMark Murray 	.d_write = randomdev_write,
77*d1b06863SMark Murray 	.d_poll = randomdev_poll,
7810cb2424SMark Murray 	.d_ioctl = randomdev_ioctl,
794db9ae91SMark Murray };
804db9ae91SMark Murray 
814db9ae91SMark Murray /* For use with make_dev(9)/destroy_dev(9). */
8289c9c53dSPoul-Henning Kamp static struct cdev *random_dev;
834db9ae91SMark Murray 
8410cb2424SMark Murray /* Set up the sysctl root node for the entropy device */
85*d1b06863SMark Murray SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator");
864db9ae91SMark Murray 
8710cb2424SMark Murray MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
884db9ae91SMark Murray 
89*d1b06863SMark Murray #if defined(RANDOM_DUMMY)
90*d1b06863SMark Murray 
91*d1b06863SMark Murray /*-
92*d1b06863SMark Murray  * Dummy "always block" pseudo algorithm, used when there is no real
93*d1b06863SMark Murray  * random(4) driver to provide a CSPRNG.
94*d1b06863SMark Murray  */
95*d1b06863SMark Murray 
96*d1b06863SMark Murray static u_int
97*d1b06863SMark Murray dummy_random_zero(void)
98*d1b06863SMark Murray {
99*d1b06863SMark Murray 
100*d1b06863SMark Murray 	return (0);
101*d1b06863SMark Murray }
102*d1b06863SMark Murray 
103*d1b06863SMark Murray static void
104*d1b06863SMark Murray dummy_random(void)
105*d1b06863SMark Murray {
106*d1b06863SMark Murray }
107*d1b06863SMark Murray 
108*d1b06863SMark Murray struct random_algorithm random_alg_context = {
109*d1b06863SMark Murray 	.ra_ident = "Dummy",
110*d1b06863SMark Murray 	.ra_reseed = dummy_random,
111*d1b06863SMark Murray 	.ra_seeded = (random_alg_seeded_t *)dummy_random_zero,
112*d1b06863SMark Murray 	.ra_pre_read = dummy_random,
113*d1b06863SMark Murray 	.ra_read = (random_alg_read_t *)dummy_random_zero,
114*d1b06863SMark Murray 	.ra_post_read = dummy_random,
115*d1b06863SMark Murray 	.ra_write = (random_alg_write_t *)dummy_random_zero,
116*d1b06863SMark Murray 	.ra_event_processor = NULL,
117*d1b06863SMark Murray 	.ra_poolcount = 0,
118*d1b06863SMark Murray };
119*d1b06863SMark Murray 
120*d1b06863SMark Murray #else /* !defined(RANDOM_DUMMY) */
121*d1b06863SMark Murray 
122*d1b06863SMark Murray LIST_HEAD(sources_head, random_sources);
123*d1b06863SMark Murray static struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list);
124*d1b06863SMark Murray static u_int read_rate;
125*d1b06863SMark Murray 
126*d1b06863SMark Murray #endif /* defined(RANDOM_DUMMY) */
127*d1b06863SMark Murray 
128*d1b06863SMark Murray static struct selinfo rsel;
129*d1b06863SMark Murray 
130*d1b06863SMark Murray /*
131*d1b06863SMark Murray  * This is the read uio(9) interface for random(4).
132*d1b06863SMark Murray  */
133*d1b06863SMark Murray /* ARGSUSED */
134*d1b06863SMark Murray static int
135*d1b06863SMark Murray randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags)
136*d1b06863SMark Murray {
137*d1b06863SMark Murray 	uint8_t *random_buf;
138*d1b06863SMark Murray 	int c, error;
139*d1b06863SMark Murray 	ssize_t nbytes;
140*d1b06863SMark Murray 
141*d1b06863SMark Murray 	random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
142*d1b06863SMark Murray 	random_alg_context.ra_pre_read();
143*d1b06863SMark Murray 	/* (Un)Blocking logic */
144*d1b06863SMark Murray 	error = 0;
145*d1b06863SMark Murray 	while (!random_alg_context.ra_seeded() && error == 0) {
146*d1b06863SMark Murray 		if (flags & O_NONBLOCK)	{
147*d1b06863SMark Murray 			error = EWOULDBLOCK;
148*d1b06863SMark Murray 			break;
149*d1b06863SMark Murray 		}
150*d1b06863SMark Murray 		tsleep(&random_alg_context, 0, "randrd", hz/10);
151*d1b06863SMark Murray 		/* keep tapping away at the pre-read until we seed/unblock. */
152*d1b06863SMark Murray 		random_alg_context.ra_pre_read();
153*d1b06863SMark Murray 		printf("random: %s unblock (error = %d)\n", __func__, error);
154*d1b06863SMark Murray 	}
155*d1b06863SMark Murray 	if (error == 0) {
156*d1b06863SMark Murray #if !defined(RANDOM_DUMMY)
157*d1b06863SMark Murray 		/* XXX: FIX!! Next line as an atomic operation? */
158*d1b06863SMark Murray 		read_rate += (uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t);
159*d1b06863SMark Murray #endif
160*d1b06863SMark Murray 		nbytes = uio->uio_resid;
161*d1b06863SMark Murray 		while (uio->uio_resid && !error) {
162*d1b06863SMark Murray 			c = MIN(uio->uio_resid, PAGE_SIZE);
163*d1b06863SMark Murray 			random_alg_context.ra_read(random_buf, c);
164*d1b06863SMark Murray 			error = uiomove(random_buf, c, uio);
165*d1b06863SMark Murray 		}
166*d1b06863SMark Murray 		random_alg_context.ra_post_read();
167*d1b06863SMark Murray 		if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR) )
168*d1b06863SMark Murray 			/* Return partial read, not error. */
169*d1b06863SMark Murray 			error = 0;
170*d1b06863SMark Murray 	}
171*d1b06863SMark Murray 	free(random_buf, M_ENTROPY);
172*d1b06863SMark Murray 	return (error);
173*d1b06863SMark Murray }
174*d1b06863SMark Murray 
175*d1b06863SMark Murray /*-
176*d1b06863SMark Murray  * Kernel API version of read_random().
177*d1b06863SMark Murray  * This is similar to random_alg_read(),
178*d1b06863SMark Murray  * except it doesn't interface with uio(9).
179*d1b06863SMark Murray  * It cannot assumed that random_buf is a multiple of
180*d1b06863SMark Murray  * RANDOM_BLOCKSIZE bytes.
181*d1b06863SMark Murray  */
182*d1b06863SMark Murray u_int
183*d1b06863SMark Murray read_random(void *random_buf, u_int len)
184*d1b06863SMark Murray {
185*d1b06863SMark Murray 	u_int read_len, total_read, c;
186*d1b06863SMark Murray 	uint8_t local_buf[len + RANDOM_BLOCKSIZE];
187*d1b06863SMark Murray 
188*d1b06863SMark Murray 	KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__));
189*d1b06863SMark Murray 	random_alg_context.ra_pre_read();
190*d1b06863SMark Murray 	/* (Un)Blocking logic; if not seeded, return nothing. */
191*d1b06863SMark Murray 	if (random_alg_context.ra_seeded()) {
192*d1b06863SMark Murray #if !defined(RANDOM_DUMMY)
193*d1b06863SMark Murray 		/* XXX: FIX!! Next line as an atomic operation? */
194*d1b06863SMark Murray 		read_rate += (len + sizeof(uint32_t))/sizeof(uint32_t);
195*d1b06863SMark Murray #endif
196*d1b06863SMark Murray 		read_len = len;
197*d1b06863SMark Murray 		total_read = 0;
198*d1b06863SMark Murray 		while (read_len) {
199*d1b06863SMark Murray 			c = MIN(read_len, PAGE_SIZE);
200*d1b06863SMark Murray 			random_alg_context.ra_read(&local_buf[total_read], c);
201*d1b06863SMark Murray 			read_len -= c;
202*d1b06863SMark Murray 			total_read += c;
203*d1b06863SMark Murray 		}
204*d1b06863SMark Murray 		memcpy(random_buf, local_buf, len);
205*d1b06863SMark Murray 	} else
206*d1b06863SMark Murray 		len = 0;
207*d1b06863SMark Murray 	random_alg_context.ra_post_read();
208*d1b06863SMark Murray 	return (len);
209*d1b06863SMark Murray }
210*d1b06863SMark Murray 
211*d1b06863SMark Murray /* ARGSUSED */
212*d1b06863SMark Murray static int
213*d1b06863SMark Murray randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
214*d1b06863SMark Murray {
215*d1b06863SMark Murray 	uint8_t *random_buf;
216*d1b06863SMark Murray 	int c, error = 0;
217*d1b06863SMark Murray 	ssize_t nbytes;
218*d1b06863SMark Murray 
219*d1b06863SMark Murray 	random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
220*d1b06863SMark Murray 	nbytes = uio->uio_resid;
221*d1b06863SMark Murray 	while (uio->uio_resid > 0 && error == 0) {
222*d1b06863SMark Murray 		c = MIN(uio->uio_resid, PAGE_SIZE);
223*d1b06863SMark Murray 		error = uiomove(random_buf, c, uio);
224*d1b06863SMark Murray 		if (error)
225*d1b06863SMark Murray 			break;
226*d1b06863SMark Murray 		random_alg_context.ra_write(random_buf, c);
227*d1b06863SMark Murray 		tsleep(&random_alg_context, 0, "randwr", hz/10);
228*d1b06863SMark Murray 	}
229*d1b06863SMark Murray 	if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR))
230*d1b06863SMark Murray 		/* Partial write, not error. */
231*d1b06863SMark Murray 		error = 0;
232*d1b06863SMark Murray 	free(random_buf, M_ENTROPY);
233*d1b06863SMark Murray 	return (error);
234*d1b06863SMark Murray }
235*d1b06863SMark Murray 
236*d1b06863SMark Murray /* ARGSUSED */
237*d1b06863SMark Murray static int
238*d1b06863SMark Murray randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
239*d1b06863SMark Murray {
240*d1b06863SMark Murray 
241*d1b06863SMark Murray 	if (events & (POLLIN | POLLRDNORM)) {
242*d1b06863SMark Murray 		if (random_alg_context.ra_seeded())
243*d1b06863SMark Murray 			events &= (POLLIN | POLLRDNORM);
244*d1b06863SMark Murray 		else
245*d1b06863SMark Murray 			selrecord(td, &rsel);
246*d1b06863SMark Murray 	}
247*d1b06863SMark Murray 	return (events);
248*d1b06863SMark Murray }
249*d1b06863SMark Murray 
250*d1b06863SMark Murray /* This will be called by the entropy processor when it seeds itself and becomes secure */
251*d1b06863SMark Murray void
252*d1b06863SMark Murray randomdev_unblock(void)
253*d1b06863SMark Murray {
254*d1b06863SMark Murray 
255*d1b06863SMark Murray 	selwakeuppri(&rsel, PUSER);
256*d1b06863SMark Murray 	wakeup(&random_alg_context);
257*d1b06863SMark Murray 	printf("random: unblocking device.\n");
258*d1b06863SMark Murray 	/* Do random(9) a favour while we are about it. */
259*d1b06863SMark Murray 	(void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE);
260*d1b06863SMark Murray }
261*d1b06863SMark Murray 
262e1199601SMark Murray /* ARGSUSED */
2634db9ae91SMark Murray static int
26410cb2424SMark Murray randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
265e1199601SMark Murray     int flags __unused, struct thread *td __unused)
2664d87a031SMark Murray {
267e7806b4cSMark Murray 	int error = 0;
268e7806b4cSMark Murray 
26941bc9751SMark Murray 	switch (cmd) {
27041bc9751SMark Murray 		/* Really handled in upper layer */
27141bc9751SMark Murray 	case FIOASYNC:
27241bc9751SMark Murray 	case FIONBIO:
273e7806b4cSMark Murray 		break;
27441bc9751SMark Murray 	default:
275e7806b4cSMark Murray 		error = ENOTTY;
2764d87a031SMark Murray 	}
27710cb2424SMark Murray 
278e7806b4cSMark Murray 	return (error);
27941bc9751SMark Murray }
2804d87a031SMark Murray 
281*d1b06863SMark Murray void
282*d1b06863SMark Murray random_source_register(struct random_source *rsource)
283*d1b06863SMark Murray {
284*d1b06863SMark Murray #if defined(RANDOM_DUMMY)
285*d1b06863SMark Murray 	(void)rsource;
286*d1b06863SMark Murray #else /* !defined(RANDOM_DUMMY) */
287*d1b06863SMark Murray 	struct random_sources *rrs;
288*d1b06863SMark Murray 
289*d1b06863SMark Murray 	KASSERT(rsource != NULL, ("invalid input to %s", __func__));
290*d1b06863SMark Murray 
291*d1b06863SMark Murray 	rrs = malloc(sizeof(*rrs), M_ENTROPY, M_WAITOK);
292*d1b06863SMark Murray 	rrs->rrs_source = rsource;
293*d1b06863SMark Murray 
294*d1b06863SMark Murray 	printf("random: registering fast source %s\n", rsource->rs_ident);
295*d1b06863SMark Murray 	LIST_INSERT_HEAD(&source_list, rrs, rrs_entries);
296*d1b06863SMark Murray #endif /* defined(RANDOM_DUMMY) */
297*d1b06863SMark Murray }
298*d1b06863SMark Murray 
299*d1b06863SMark Murray void
300*d1b06863SMark Murray random_source_deregister(struct random_source *rsource)
301*d1b06863SMark Murray {
302*d1b06863SMark Murray #if defined(RANDOM_DUMMY)
303*d1b06863SMark Murray 	(void)rsource;
304*d1b06863SMark Murray #else /* !defined(RANDOM_DUMMY) */
305*d1b06863SMark Murray 	struct random_sources *rrs = NULL;
306*d1b06863SMark Murray 
307*d1b06863SMark Murray 	KASSERT(rsource != NULL, ("invalid input to %s", __func__));
308*d1b06863SMark Murray 	LIST_FOREACH(rrs, &source_list, rrs_entries)
309*d1b06863SMark Murray 		if (rrs->rrs_source == rsource) {
310*d1b06863SMark Murray 			LIST_REMOVE(rrs, rrs_entries);
311*d1b06863SMark Murray 			break;
312*d1b06863SMark Murray 		}
313*d1b06863SMark Murray 	if (rrs != NULL)
314*d1b06863SMark Murray 		free(rrs, M_ENTROPY);
315*d1b06863SMark Murray #endif /* defined(RANDOM_DUMMY) */
316*d1b06863SMark Murray }
317*d1b06863SMark Murray 
318*d1b06863SMark Murray #if !defined(RANDOM_DUMMY)
319*d1b06863SMark Murray /*
320*d1b06863SMark Murray  * Run through all fast sources reading entropy for the given
321*d1b06863SMark Murray  * number of rounds, which should be a multiple of the number
322*d1b06863SMark Murray  * of entropy accumulation pools in use; 2 for Yarrow and 32
323*d1b06863SMark Murray  * for Fortuna.
324*d1b06863SMark Murray  *
325*d1b06863SMark Murray  * BEWARE!!!
326*d1b06863SMark Murray  * This function runs inside the RNG thread! Don't do anything silly!
32710cb2424SMark Murray  */
32810cb2424SMark Murray void
329*d1b06863SMark Murray random_sources_feed(void)
330a6278a2aSMark Murray {
331*d1b06863SMark Murray 	uint32_t entropy[HARVESTSIZE];
332*d1b06863SMark Murray 	struct random_sources *rrs;
333*d1b06863SMark Murray 	u_int i, n, local_read_rate;
334a6278a2aSMark Murray 
335*d1b06863SMark Murray 	/*
336*d1b06863SMark Murray 	 * Step over all of live entropy sources, and feed their output
337*d1b06863SMark Murray 	 * to the system-wide RNG.
338*d1b06863SMark Murray 	 */
339*d1b06863SMark Murray 	/* XXX: FIX!! Next lines as an atomic operation? */
340*d1b06863SMark Murray 	local_read_rate = read_rate;
341*d1b06863SMark Murray 	read_rate = RANDOM_ALG_READ_RATE_MINIMUM;
342*d1b06863SMark Murray 	LIST_FOREACH(rrs, &source_list, rrs_entries) {
343*d1b06863SMark Murray 		for (i = 0; i < random_alg_context.ra_poolcount*local_read_rate; i++) {
344*d1b06863SMark Murray 			n = rrs->rrs_source->rs_read(entropy, sizeof(entropy));
345*d1b06863SMark Murray 			KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__));
346*d1b06863SMark Murray 			random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source);
3475711939bSDavid E. O'Brien 		}
348*d1b06863SMark Murray 	}
349*d1b06863SMark Murray 	explicit_bzero(entropy, sizeof(entropy));
350*d1b06863SMark Murray }
351*d1b06863SMark Murray 
352*d1b06863SMark Murray static int
353*d1b06863SMark Murray random_source_handler(SYSCTL_HANDLER_ARGS)
354*d1b06863SMark Murray {
355*d1b06863SMark Murray 	struct random_sources *rrs;
356*d1b06863SMark Murray 	struct sbuf sbuf;
357*d1b06863SMark Murray 	int error, count;
358*d1b06863SMark Murray 
359*d1b06863SMark Murray 	sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
360*d1b06863SMark Murray 	count = 0;
361*d1b06863SMark Murray 	LIST_FOREACH(rrs, &source_list, rrs_entries) {
362*d1b06863SMark Murray 		sbuf_cat(&sbuf, (count++ ? ",'" : "'"));
363*d1b06863SMark Murray 		sbuf_cat(&sbuf, rrs->rrs_source->rs_ident);
364*d1b06863SMark Murray 		sbuf_cat(&sbuf, "'");
365*d1b06863SMark Murray 	}
366*d1b06863SMark Murray 	error = sbuf_finish(&sbuf);
367*d1b06863SMark Murray 	sbuf_delete(&sbuf);
368*d1b06863SMark Murray 	return (error);
369*d1b06863SMark Murray }
370*d1b06863SMark Murray SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
371*d1b06863SMark Murray 	    NULL, 0, random_source_handler, "A",
372*d1b06863SMark Murray 	    "List of active fast entropy sources.");
373*d1b06863SMark Murray #endif /* !defined(RANDOM_DUMMY) */
3745711939bSDavid E. O'Brien 
375e1199601SMark Murray /* ARGSUSED */
376a6278a2aSMark Murray static int
37710cb2424SMark Murray randomdev_modevent(module_t mod __unused, int type, void *data __unused)
3784db9ae91SMark Murray {
379e7806b4cSMark Murray 	int error = 0;
3804d87a031SMark Murray 
3814db9ae91SMark Murray 	switch (type) {
3824db9ae91SMark Murray 	case MOD_LOAD:
383*d1b06863SMark Murray 		printf("random: entropy device external interface\n");
38410cb2424SMark Murray 		random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
38510cb2424SMark Murray 		    RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0644, "random");
38610cb2424SMark Murray 		make_dev_alias(random_dev, "urandom"); /* compatibility */
387e7806b4cSMark Murray 		break;
3884db9ae91SMark Murray 	case MOD_UNLOAD:
389c9ec235cSMark Murray 		destroy_dev(random_dev);
390e7806b4cSMark Murray 		break;
3914db9ae91SMark Murray 	case MOD_SHUTDOWN:
392e7806b4cSMark Murray 		break;
3933e019deaSPoul-Henning Kamp 	default:
3943e019deaSPoul-Henning Kamp 		error = EOPNOTSUPP;
3953e019deaSPoul-Henning Kamp 		break;
3964db9ae91SMark Murray 	}
397e7806b4cSMark Murray 	return (error);
3984db9ae91SMark Murray }
3994db9ae91SMark Murray 
400*d1b06863SMark Murray static moduledata_t randomdev_mod = {
401*d1b06863SMark Murray 	"random_device",
402*d1b06863SMark Murray 	randomdev_modevent,
403*d1b06863SMark Murray 	0
404*d1b06863SMark Murray };
40510cb2424SMark Murray 
406*d1b06863SMark Murray DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
407*d1b06863SMark Murray MODULE_VERSION(random_device, 1);
408