randomdev.c revision 65686
162053Smarkm/*-
262765Smarkm * Copyright (c) 2000 Mark R V Murray
362053Smarkm * All rights reserved.
462053Smarkm *
562053Smarkm * Redistribution and use in source and binary forms, with or without
662053Smarkm * modification, are permitted provided that the following conditions
762053Smarkm * are met:
862053Smarkm * 1. Redistributions of source code must retain the above copyright
962053Smarkm *    notice, this list of conditions and the following disclaimer
1062053Smarkm *    in this position and unchanged.
1162053Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1262053Smarkm *    notice, this list of conditions and the following disclaimer in the
1362053Smarkm *    documentation and/or other materials provided with the distribution.
1462053Smarkm *
1562053Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1662053Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1762053Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1862053Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1962053Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2062053Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2162053Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2262053Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2362053Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2462053Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2562053Smarkm *
2662053Smarkm * $FreeBSD: head/sys/dev/random/randomdev.c 65686 2000-09-10 13:52:19Z markm $
2762053Smarkm */
2862053Smarkm
2962053Smarkm#include <sys/param.h>
3062765Smarkm#include <sys/queue.h>
3162053Smarkm#include <sys/systm.h>
3262053Smarkm#include <sys/conf.h>
3362053Smarkm#include <sys/fcntl.h>
3462053Smarkm#include <sys/uio.h>
3562053Smarkm#include <sys/kernel.h>
3662053Smarkm#include <sys/malloc.h>
3762053Smarkm#include <sys/module.h>
3862053Smarkm#include <sys/bus.h>
3962053Smarkm#include <sys/random.h>
4062053Smarkm#include <machine/bus.h>
4162053Smarkm#include <machine/resource.h>
4262053Smarkm#include <sys/rman.h>
4362053Smarkm#include <sys/signalvar.h>
4462053Smarkm#include <sys/sysctl.h>
4562053Smarkm#include <crypto/blowfish/blowfish.h>
4662053Smarkm
4765686Smarkm#include <dev/randomdev/hash.h>
4862117Smarkm#include <dev/randomdev/yarrow.h>
4962053Smarkm
5063855Smarkmstatic d_open_t random_open;
5162765Smarkmstatic d_read_t random_read;
5262765Smarkmstatic d_write_t random_write;
5365686Smarkmstatic d_ioctl_t random_ioctl;
5462053Smarkm
5562053Smarkm#define CDEV_MAJOR	2
5662053Smarkm#define RANDOM_MINOR	3
5762149Smarkm#define URANDOM_MINOR	4
5862053Smarkm
5962053Smarkmstatic struct cdevsw random_cdevsw = {
6063855Smarkm	/* open */	random_open,
6162053Smarkm	/* close */	(d_close_t *)nullop,
6262765Smarkm	/* read */	random_read,
6362765Smarkm	/* write */	random_write,
6465686Smarkm	/* ioctl */	random_ioctl,
6562053Smarkm	/* poll */	nopoll,
6662053Smarkm	/* mmap */	nommap,
6762053Smarkm	/* strategy */	nostrategy,
6862053Smarkm	/* name */	"random",
6962053Smarkm	/* maj */	CDEV_MAJOR,
7062053Smarkm	/* dump */	nodump,
7162053Smarkm	/* psize */	nopsize,
7262053Smarkm	/* flags */	0,
7362053Smarkm	/* bmaj */	-1
7462053Smarkm};
7562053Smarkm
7662053Smarkm/* For use with make_dev(9)/destroy_dev(9). */
7762765Smarkmstatic dev_t random_dev;
7865686Smarkmstatic dev_t urandom_dev; /* XXX Temporary */
7962053Smarkm
8062053SmarkmSYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator");
8162053SmarkmSYSCTL_NODE(_kern_random, OID_AUTO, yarrow, CTLFLAG_RW, 0, "Yarrow Parameters");
8262840SmarkmSYSCTL_INT(_kern_random_yarrow, OID_AUTO, gengateinterval, CTLFLAG_RW,
8362840Smarkm	&random_state.gengateinterval, 10, "Generator Gate Interval");
8462840SmarkmSYSCTL_INT(_kern_random_yarrow, OID_AUTO, bins, CTLFLAG_RW,
8562840Smarkm	&random_state.bins, 10, "Execution time tuner");
8662840SmarkmSYSCTL_INT(_kern_random_yarrow, OID_AUTO, fastthresh, CTLFLAG_RW,
8762840Smarkm	&random_state.pool[0].thresh, 100, "Fast pool reseed threshhold");
8862840SmarkmSYSCTL_INT(_kern_random_yarrow, OID_AUTO, slowthresh, CTLFLAG_RW,
8963855Smarkm	&random_state.pool[1].thresh, 160, "Slow pool reseed threshhold");
9062840SmarkmSYSCTL_INT(_kern_random_yarrow, OID_AUTO, slowoverthresh, CTLFLAG_RW,
9162840Smarkm	&random_state.slowoverthresh, 2, "Slow pool over-threshhold reseed");
9262053Smarkm
9362053Smarkmstatic int
9463855Smarkmrandom_open(dev_t dev, int flags, int fmt, struct proc *p)
9563855Smarkm{
9663855Smarkm	if ((flags & FWRITE) && (securelevel > 0 || suser(p)))
9763855Smarkm		return EPERM;
9863855Smarkm	else
9963855Smarkm		return 0;
10063855Smarkm}
10163855Smarkm
10263855Smarkmstatic int
10362765Smarkmrandom_read(dev_t dev, struct uio *uio, int flag)
10462053Smarkm{
10562053Smarkm	u_int c, ret;
10662053Smarkm	int error = 0;
10762840Smarkm	void *random_buf;
10862053Smarkm
10962053Smarkm	c = min(uio->uio_resid, PAGE_SIZE);
11062765Smarkm	random_buf = (void *)malloc(c, M_TEMP, M_WAITOK);
11162053Smarkm	while (uio->uio_resid > 0 && error == 0) {
11265686Smarkm		ret = read_random(uio->uio_procp, random_buf, c);
11362765Smarkm		error = uiomove(random_buf, ret, uio);
11462053Smarkm	}
11562765Smarkm	free(random_buf, M_TEMP);
11662053Smarkm	return error;
11762053Smarkm}
11862053Smarkm
11962053Smarkmstatic int
12062765Smarkmrandom_write(dev_t dev, struct uio *uio, int flag)
12162053Smarkm{
12262053Smarkm	u_int c;
12362053Smarkm	int error = 0;
12462840Smarkm	void *random_buf;
12562053Smarkm
12662765Smarkm	random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
12762053Smarkm	while (uio->uio_resid > 0) {
12862053Smarkm		c = min(uio->uio_resid, PAGE_SIZE);
12962765Smarkm		error = uiomove(random_buf, c, uio);
13062053Smarkm		if (error)
13162053Smarkm			break;
13263306Smarkm		write_random(random_buf, c);
13362053Smarkm	}
13462765Smarkm	free(random_buf, M_TEMP);
13562053Smarkm	return error;
13662053Smarkm}
13762053Smarkm
13862053Smarkmstatic int
13965686Smarkmrandom_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
14065686Smarkm{
14165686Smarkm	return ENOTTY;
14265686Smarkm}
14365686Smarkm
14465686Smarkmstatic int
14562053Smarkmrandom_modevent(module_t mod, int type, void *data)
14662053Smarkm{
14765686Smarkm	int error;
14865686Smarkm
14962053Smarkm	switch(type) {
15062053Smarkm	case MOD_LOAD:
15165686Smarkm		error = random_init();
15265686Smarkm		if (error != 0)
15365686Smarkm			return error;
15462053Smarkm		if (bootverbose)
15562053Smarkm			printf("random: <entropy source>\n");
15662765Smarkm		random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, UID_ROOT,
15762149Smarkm			GID_WHEEL, 0666, "random");
15862765Smarkm		urandom_dev = make_dev(&random_cdevsw, URANDOM_MINOR, UID_ROOT,
15965686Smarkm			GID_WHEEL, 0666, "urandom"); /* XXX Temporary */
16062053Smarkm		return 0;
16162053Smarkm
16262053Smarkm	case MOD_UNLOAD:
16362765Smarkm		random_deinit();
16462765Smarkm		destroy_dev(random_dev);
16565686Smarkm		destroy_dev(urandom_dev); /* XXX Temporary */
16662053Smarkm		return 0;
16762053Smarkm
16862053Smarkm	case MOD_SHUTDOWN:
16962053Smarkm		return 0;
17062053Smarkm
17162053Smarkm	default:
17262053Smarkm		return EOPNOTSUPP;
17362053Smarkm	}
17462053Smarkm}
17562053Smarkm
17662053SmarkmDEV_MODULE(random, random_modevent, NULL);
177