randomdev.c revision 132199
1203790Sfabient/*-
2330449Seadler * Copyright (c) 2000-2004 Mark R V Murray
3330449Seadler * All rights reserved.
4203790Sfabient *
5203790Sfabient * Redistribution and use in source and binary forms, with or without
6203790Sfabient * modification, are permitted provided that the following conditions
7203790Sfabient * are met:
8203790Sfabient * 1. Redistributions of source code must retain the above copyright
9203790Sfabient *    notice, this list of conditions and the following disclaimer
10203790Sfabient *    in this position and unchanged.
11203790Sfabient * 2. Redistributions in binary form must reproduce the above copyright
12203790Sfabient *    notice, this list of conditions and the following disclaimer in the
13203790Sfabient *    documentation and/or other materials provided with the distribution.
14203790Sfabient *
15203790Sfabient * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16203790Sfabient * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17203790Sfabient * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18203790Sfabient * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19203790Sfabient * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20203790Sfabient * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21203790Sfabient * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22203790Sfabient * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23203790Sfabient * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24203790Sfabient * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25203790Sfabient *
26203790Sfabient */
27203790Sfabient
28203790Sfabient#include <sys/cdefs.h>
29203790Sfabient__FBSDID("$FreeBSD: head/sys/dev/random/randomdev.c 132199 2004-07-15 08:26:07Z phk $");
30203790Sfabient
31203790Sfabient#include <sys/param.h>
32203790Sfabient#include <sys/systm.h>
33203790Sfabient#include <sys/bus.h>
34203790Sfabient#include <sys/conf.h>
35203790Sfabient#include <sys/fcntl.h>
36203790Sfabient#include <sys/filio.h>
37203790Sfabient#include <sys/kernel.h>
38203790Sfabient#include <sys/kthread.h>
39203790Sfabient#include <sys/lock.h>
40203790Sfabient#include <sys/malloc.h>
41203790Sfabient#include <sys/module.h>
42203790Sfabient#include <sys/mutex.h>
43203790Sfabient#include <sys/poll.h>
44203790Sfabient#include <sys/proc.h>
45203790Sfabient#include <sys/selinfo.h>
46203790Sfabient#include <sys/uio.h>
47203790Sfabient#include <sys/unistd.h>
48203790Sfabient#include <sys/vnode.h>
49203790Sfabient
50203790Sfabient#include <machine/bus.h>
51203790Sfabient#include <machine/cpu.h>
52203790Sfabient
53203790Sfabient#include <dev/random/randomdev.h>
54203790Sfabient
55203790Sfabient#define RANDOM_MINOR	0
56203790Sfabient
57203790Sfabientstatic d_close_t random_close;
58203790Sfabientstatic d_read_t random_read;
59203790Sfabientstatic d_write_t random_write;
60203790Sfabientstatic d_ioctl_t random_ioctl;
61203790Sfabientstatic d_poll_t random_poll;
62203790Sfabient
63203790Sfabientstatic struct cdevsw random_cdevsw = {
64203790Sfabient	.d_version = D_VERSION,
65203790Sfabient	.d_flags = D_NEEDGIANT,
66203790Sfabient	.d_close = random_close,
67203790Sfabient	.d_read = random_read,
68203790Sfabient	.d_write = random_write,
69203790Sfabient	.d_ioctl = random_ioctl,
70203790Sfabient	.d_poll = random_poll,
71203790Sfabient	.d_name = "random",
72203790Sfabient};
73203790Sfabient
74203790Sfabientstruct random_systat random_systat;
75203790Sfabient
76203790Sfabient/* For use with make_dev(9)/destroy_dev(9). */
77203790Sfabientstatic struct cdev *random_dev;
78203790Sfabient
79291016Sjtl/* Used to fake out unused random calls in random_systat */
80291016Sjtlvoid
81291016Sjtlrandom_null_func(void)
82291016Sjtl{
83291016Sjtl}
84291016Sjtl
85291016Sjtl/* ARGSUSED */
86291016Sjtlstatic int
87203790Sfabientrandom_close(struct cdev *dev __unused, int flags, int fmt __unused,
88203790Sfabient    struct thread *td)
89203790Sfabient{
90203790Sfabient	if ((flags & FWRITE) && (suser(td) == 0)
91203790Sfabient	    && (securelevel_gt(td->td_ucred, 0) == 0)) {
92203790Sfabient		(*random_systat.reseed)();
93203790Sfabient		random_systat.seeded = 1;
94203790Sfabient	}
95203790Sfabient
96203790Sfabient	return (0);
97203790Sfabient}
98203790Sfabient
99203790Sfabient/* ARGSUSED */
100203790Sfabientstatic int
101203790Sfabientrandom_read(struct cdev *dev __unused, struct uio *uio, int flag)
102203790Sfabient{
103203790Sfabient	int c, error = 0;
104203790Sfabient	void *random_buf;
105203790Sfabient
106203790Sfabient	/* Blocking logic */
107203790Sfabient	while (!random_systat.seeded && !error) {
108203790Sfabient		if (flag & IO_NDELAY)
109203790Sfabient			error = EWOULDBLOCK;
110203790Sfabient		else {
111203790Sfabient			/* No complaints please. This is temporary! */
112203790Sfabient			printf("Entropy device is blocking. "
113203790Sfabient			    "Dance fandango on keyboard to unblock.\n");
114203790Sfabient			error = tsleep(&random_systat,
115203790Sfabient			    PUSER | PCATCH, "block", 0);
116203790Sfabient		}
117203790Sfabient	}
118203790Sfabient
119203790Sfabient	/* The actual read */
120203790Sfabient	if (!error) {
121203790Sfabient
122203790Sfabient		random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
123203790Sfabient
124203790Sfabient		while (uio->uio_resid > 0 && !error) {
125203790Sfabient			c = MIN(uio->uio_resid, PAGE_SIZE);
126203790Sfabient			c = (*random_systat.read)(random_buf, c);
127203790Sfabient			error = uiomove(random_buf, c, uio);
128203790Sfabient		}
129203790Sfabient
130203790Sfabient		free(random_buf, M_TEMP);
131203790Sfabient
132203790Sfabient	}
133203790Sfabient
134203790Sfabient	return (error);
135203790Sfabient}
136203790Sfabient
137203790Sfabient/* ARGSUSED */
138203790Sfabientstatic int
139291016Sjtlrandom_write(struct cdev *dev __unused, struct uio *uio, int flag __unused)
140203790Sfabient{
141203790Sfabient	int c, error = 0;
142291016Sjtl	void *random_buf;
143291016Sjtl
144291016Sjtl	random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
145291016Sjtl
146203790Sfabient	while (uio->uio_resid > 0) {
147203790Sfabient		c = MIN((int)uio->uio_resid, PAGE_SIZE);
148203790Sfabient		error = uiomove(random_buf, c, uio);
149203790Sfabient		if (error)
150203790Sfabient			break;
151203790Sfabient		(*random_systat.write)(random_buf, c);
152203790Sfabient	}
153203790Sfabient
154203790Sfabient	free(random_buf, M_TEMP);
155203790Sfabient
156203790Sfabient	return (error);
157203790Sfabient}
158203790Sfabient
159203790Sfabient/* ARGSUSED */
160203790Sfabientstatic int
161203790Sfabientrandom_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
162203790Sfabient    int flags __unused, struct thread *td __unused)
163203790Sfabient{
164203790Sfabient	int error = 0;
165203790Sfabient
166203790Sfabient	switch (cmd) {
167203790Sfabient		/* Really handled in upper layer */
168203790Sfabient	case FIOASYNC:
169203790Sfabient	case FIONBIO:
170203790Sfabient		break;
171203790Sfabient	default:
172203790Sfabient		error = ENOTTY;
173203790Sfabient	}
174203790Sfabient	return (error);
175203790Sfabient}
176203790Sfabient
177203790Sfabient/* ARGSUSED */
178203790Sfabientstatic int
179203790Sfabientrandom_poll(struct cdev *dev __unused, int events, struct thread *td)
180203790Sfabient{
181203790Sfabient	int revents = 0;
182203790Sfabient
183203790Sfabient	if (events & (POLLIN | POLLRDNORM)) {
184203790Sfabient		if (random_systat.seeded)
185203790Sfabient			revents = events & (POLLIN | POLLRDNORM);
186206635Sfabient		else
187206635Sfabient			selrecord(td, &random_systat.rsel);
188203790Sfabient	}
189203790Sfabient	return (revents);
190203790Sfabient}
191203790Sfabient
192203790Sfabient/* ARGSUSED */
193203790Sfabientstatic int
194203790Sfabientrandom_modevent(module_t mod __unused, int type, void *data __unused)
195203790Sfabient{
196203790Sfabient	int error = 0;
197203790Sfabient
198203790Sfabient	switch (type) {
199203790Sfabient	case MOD_LOAD:
200203790Sfabient		random_ident_hardware(&random_systat);
201203790Sfabient		(*random_systat.init)();
202203790Sfabient
203203790Sfabient		if (bootverbose)
204203790Sfabient			printf("random: <entropy source, %s>\n",
205203790Sfabient			    random_systat.ident);
206203790Sfabient
207203790Sfabient		random_dev = make_dev(&random_cdevsw, RANDOM_MINOR,
208203790Sfabient		    UID_ROOT, GID_WHEEL, 0666, "random");
209203790Sfabient		make_dev_alias(random_dev, "urandom");	/* XXX Deprecated */
210203790Sfabient
211203790Sfabient		break;
212203790Sfabient
213203790Sfabient	case MOD_UNLOAD:
214203790Sfabient		(*random_systat.deinit)();
215203790Sfabient
216203790Sfabient		destroy_dev(random_dev);
217203790Sfabient
218203790Sfabient		break;
219203790Sfabient
220203790Sfabient	case MOD_SHUTDOWN:
221203790Sfabient		break;
222203790Sfabient
223203790Sfabient	default:
224203790Sfabient		error = EOPNOTSUPP;
225203790Sfabient		break;
226203790Sfabient
227203790Sfabient	}
228203790Sfabient	return (error);
229203790Sfabient}
230203790Sfabient
231203790SfabientDEV_MODULE(random, random_modevent, NULL);
232203790Sfabient