randomdev.c revision 69172
1338530Sdelphij/*-
2275970Scy * Copyright (c) 2000 Mark R V Murray
3275970Scy * All rights reserved.
4275970Scy *
5275970Scy * Redistribution and use in source and binary forms, with or without
6338530Sdelphij * modification, are permitted provided that the following conditions
7275970Scy * are met:
8275970Scy * 1. Redistributions of source code must retain the above copyright
9275970Scy *    notice, this list of conditions and the following disclaimer
10275970Scy *    in this position and unchanged.
11275970Scy * 2. Redistributions in binary form must reproduce the above copyright
12275970Scy *    notice, this list of conditions and the following disclaimer in the
13275970Scy *    documentation and/or other materials provided with the distribution.
14275970Scy *
15275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24330106Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25330106Sdelphij *
26330106Sdelphij * $FreeBSD: head/sys/dev/random/randomdev.c 69172 2000-11-25 19:13:29Z markm $
27330106Sdelphij */
28275970Scy
29330106Sdelphij#include <sys/param.h>
30275970Scy#include <sys/queue.h>
31275970Scy#include <sys/systm.h>
32330106Sdelphij#include <sys/conf.h>
33330106Sdelphij#include <sys/fcntl.h>
34330106Sdelphij#include <sys/uio.h>
35330106Sdelphij#include <sys/kernel.h>
36275970Scy#include <sys/malloc.h>
37275970Scy#include <sys/module.h>
38275970Scy#include <sys/bus.h>
39330106Sdelphij#include <sys/poll.h>
40330106Sdelphij#include <sys/select.h>
41330106Sdelphij#include <sys/random.h>
42330106Sdelphij#include <sys/vnode.h>
43275970Scy#include <machine/bus.h>
44330106Sdelphij#include <machine/resource.h>
45330106Sdelphij#include <sys/sysctl.h>
46330106Sdelphij#include <crypto/blowfish/blowfish.h>
47275970Scy
48275970Scy#include <dev/random/hash.h>
49275970Scy#include <dev/random/yarrow.h>
50275970Scy
51275970Scy#include "opt_noblockrandom.h"
52275970Scy
53275970Scystatic d_open_t random_open;
54275970Scystatic d_close_t random_close;
55275970Scystatic d_read_t random_read;
56275970Scystatic d_write_t random_write;
57275970Scystatic d_ioctl_t random_ioctl;
58275970Scystatic d_poll_t random_poll;
59275970Scy
60275970Scy#define CDEV_MAJOR	2
61275970Scy#define RANDOM_MINOR	3
62275970Scy#define URANDOM_MINOR	4
63275970Scy
64275970Scystatic struct cdevsw random_cdevsw = {
65275970Scy	/* open */	random_open,
66330106Sdelphij	/* close */	random_close,
67275970Scy	/* read */	random_read,
68330106Sdelphij	/* write */	random_write,
69275970Scy	/* ioctl */	random_ioctl,
70330106Sdelphij	/* poll */	random_poll,
71330106Sdelphij	/* mmap */	nommap,
72330106Sdelphij	/* strategy */	nostrategy,
73330106Sdelphij	/* name */	"random",
74330106Sdelphij	/* maj */	CDEV_MAJOR,
75330106Sdelphij	/* dump */	nodump,
76330106Sdelphij	/* psize */	nopsize,
77330106Sdelphij	/* flags */	0,
78330106Sdelphij	/* bmaj */	-1
79330106Sdelphij};
80275970Scy
81275970Scy/* For use with make_dev(9)/destroy_dev(9). */
82330106Sdelphijstatic dev_t random_dev;
83275970Scystatic dev_t urandom_dev; /* XXX Temporary */
84330106Sdelphij
85330106SdelphijSYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator");
86275970ScySYSCTL_NODE(_kern_random, OID_AUTO, yarrow, CTLFLAG_RW, 0, "Yarrow Parameters");
87275970ScySYSCTL_INT(_kern_random_yarrow, OID_AUTO, gengateinterval, CTLFLAG_RW,
88330106Sdelphij	&random_state.gengateinterval, 10, "Generator Gate Interval");
89275970ScySYSCTL_INT(_kern_random_yarrow, OID_AUTO, bins, CTLFLAG_RW,
90330106Sdelphij	&random_state.bins, 10, "Execution time tuner");
91275970ScySYSCTL_INT(_kern_random_yarrow, OID_AUTO, fastthresh, CTLFLAG_RW,
92330106Sdelphij	&random_state.pool[0].thresh, 100, "Fast pool reseed threshhold");
93330106SdelphijSYSCTL_INT(_kern_random_yarrow, OID_AUTO, slowthresh, CTLFLAG_RW,
94330106Sdelphij	&random_state.pool[1].thresh, 160, "Slow pool reseed threshhold");
95330106SdelphijSYSCTL_INT(_kern_random_yarrow, OID_AUTO, slowoverthresh, CTLFLAG_RW,
96275970Scy	&random_state.slowoverthresh, 2, "Slow pool over-threshhold reseed");
97275970Scy
98275970Scystatic int
99275970Scyrandom_open(dev_t dev, int flags, int fmt, struct proc *p)
100275970Scy{
101330106Sdelphij	if ((flags & FWRITE) && (securelevel > 0 || suser(p)))
102275970Scy		return EPERM;
103275970Scy	else
104275970Scy		return 0;
105275970Scy}
106275970Scy
107275970Scystatic int
108330106Sdelphijrandom_close(dev_t dev, int flags, int fmt, struct proc *p)
109330106Sdelphij{
110330106Sdelphij	if ((flags & FWRITE) && (securelevel > 0 || suser(p)))
111330106Sdelphij		random_reseed();
112330106Sdelphij	return 0;
113330106Sdelphij}
114330106Sdelphij
115275970Scystatic int
116275970Scyrandom_read(dev_t dev, struct uio *uio, int flag)
117275970Scy{
118330106Sdelphij	u_int c, ret;
119275970Scy	int error = 0;
120330106Sdelphij	void *random_buf;
121275970Scy
122275970Scy/* XXX Temporary ifndef to allow users to have a nonblocking device */
123275970Scy#ifndef NOBLOCKRANDOM
124330106Sdelphij	while (!random_state.seeded) {
125275970Scy		if (flag & IO_NDELAY)
126275970Scy			error =  EWOULDBLOCK;
127330106Sdelphij		else
128275970Scy			error = tsleep(&random_state, PUSER|PCATCH, "rndblk", 0);
129275970Scy		if (error != 0)
130275970Scy			return error;
131275970Scy	}
132275970Scy#endif
133330106Sdelphij	c = min(uio->uio_resid, PAGE_SIZE);
134330106Sdelphij	random_buf = (void *)malloc(c, M_TEMP, M_WAITOK);
135330106Sdelphij	while (uio->uio_resid > 0 && error == 0) {
136275970Scy		ret = read_random_real(random_buf, c);
137275970Scy		error = uiomove(random_buf, ret, uio);
138330106Sdelphij	}
139330106Sdelphij	free(random_buf, M_TEMP);
140330106Sdelphij	return error;
141330106Sdelphij}
142330106Sdelphij
143330106Sdelphijstatic int
144330106Sdelphijrandom_write(dev_t dev, struct uio *uio, int flag)
145330106Sdelphij{
146330106Sdelphij	u_int c;
147330106Sdelphij	int error = 0;
148330106Sdelphij	void *random_buf;
149330106Sdelphij
150330106Sdelphij	random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
151330106Sdelphij	while (uio->uio_resid > 0) {
152330106Sdelphij		c = min(uio->uio_resid, PAGE_SIZE);
153275970Scy		error = uiomove(random_buf, c, uio);
154275970Scy		if (error)
155275970Scy			break;
156330106Sdelphij		write_random(random_buf, c);
157330106Sdelphij	}
158330106Sdelphij	free(random_buf, M_TEMP);
159275970Scy	return error;
160330106Sdelphij}
161330106Sdelphij
162330106Sdelphijstatic int
163275970Scyrandom_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
164275970Scy{
165330106Sdelphij	return ENOTTY;
166330106Sdelphij}
167330106Sdelphij
168330106Sdelphijstatic int
169330106Sdelphijrandom_poll(dev_t dev, int events, struct proc *p)
170330106Sdelphij{
171330106Sdelphij	int revents;
172330106Sdelphij
173275970Scy	revents = 0;
174330106Sdelphij	if (events & (POLLIN | POLLRDNORM)) {
175330106Sdelphij		if (random_state.seeded)
176330106Sdelphij			revents = events & (POLLIN | POLLRDNORM);
177330106Sdelphij		else
178330106Sdelphij			selrecord(p, &random_state.rsel);
179275970Scy	}
180275970Scy	return revents;
181330106Sdelphij}
182330106Sdelphij
183330106Sdelphijstatic int
184330106Sdelphijrandom_modevent(module_t mod, int type, void *data)
185330106Sdelphij{
186330106Sdelphij	int error;
187330106Sdelphij
188330106Sdelphij	switch(type) {
189330106Sdelphij	case MOD_LOAD:
190330106Sdelphij		error = random_init();
191275970Scy		if (error != 0)
192275970Scy			return error;
193275970Scy		if (bootverbose)
194275970Scy			printf("random: <entropy source>\n");
195275970Scy		random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, UID_ROOT,
196275970Scy			GID_WHEEL, 0666, "random");
197275970Scy		urandom_dev = make_dev(&random_cdevsw, URANDOM_MINOR, UID_ROOT,
198275970Scy			GID_WHEEL, 0666, "urandom"); /* XXX Temporary */
199275970Scy		return 0;
200275970Scy
201330106Sdelphij	case MOD_UNLOAD:
202275970Scy		random_deinit();
203275970Scy		destroy_dev(random_dev);
204275970Scy		destroy_dev(urandom_dev); /* XXX Temporary */
205330106Sdelphij		return 0;
206275970Scy
207275970Scy	case MOD_SHUTDOWN:
208330106Sdelphij		return 0;
209275970Scy
210275970Scy	default:
211330106Sdelphij		return EOPNOTSUPP;
212275970Scy	}
213330106Sdelphij}
214275970Scy
215275970ScyDEV_MODULE(random, random_modevent, NULL);
216275970Scy