randomdev.c revision 71037
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 71037 2001-01-14 17:50:15Z 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> 3967112Smarkm#include <sys/poll.h> 4070834Swollman#include <sys/selinfo.h> 4162053Smarkm#include <sys/random.h> 4271037Smarkm#include <sys/sysctl.h> 4367112Smarkm#include <sys/vnode.h> 4462053Smarkm#include <machine/bus.h> 4562053Smarkm#include <machine/resource.h> 4662053Smarkm#include <crypto/blowfish/blowfish.h> 4762053Smarkm 4867112Smarkm#include <dev/random/hash.h> 4967112Smarkm#include <dev/random/yarrow.h> 5062053Smarkm 5163855Smarkmstatic d_open_t random_open; 5269172Smarkmstatic d_close_t random_close; 5362765Smarkmstatic d_read_t random_read; 5462765Smarkmstatic d_write_t random_write; 5565686Smarkmstatic d_ioctl_t random_ioctl; 5667112Smarkmstatic d_poll_t random_poll; 5762053Smarkm 5862053Smarkm#define CDEV_MAJOR 2 5962053Smarkm#define RANDOM_MINOR 3 6062149Smarkm#define URANDOM_MINOR 4 6162053Smarkm 6262053Smarkmstatic struct cdevsw random_cdevsw = { 6363855Smarkm /* open */ random_open, 6469172Smarkm /* close */ random_close, 6562765Smarkm /* read */ random_read, 6662765Smarkm /* write */ random_write, 6765686Smarkm /* ioctl */ random_ioctl, 6867112Smarkm /* poll */ random_poll, 6962053Smarkm /* mmap */ nommap, 7062053Smarkm /* strategy */ nostrategy, 7162053Smarkm /* name */ "random", 7262053Smarkm /* maj */ CDEV_MAJOR, 7362053Smarkm /* dump */ nodump, 7462053Smarkm /* psize */ nopsize, 7562053Smarkm /* flags */ 0, 7662053Smarkm /* bmaj */ -1 7762053Smarkm}; 7862053Smarkm 7962053Smarkm/* For use with make_dev(9)/destroy_dev(9). */ 8062765Smarkmstatic dev_t random_dev; 8165686Smarkmstatic dev_t urandom_dev; /* XXX Temporary */ 8262053Smarkm 8371037Smarkm/* To stash the sysctl's until they are removed */ 8471037Smarkmstatic struct sysctl_oid *random_sysctl[10]; /* magic # is sysctl count */ 8571037Smarkmstatic int sysctlcount = 0; 8662053Smarkm 8762053Smarkmstatic int 8863855Smarkmrandom_open(dev_t dev, int flags, int fmt, struct proc *p) 8963855Smarkm{ 9063855Smarkm if ((flags & FWRITE) && (securelevel > 0 || suser(p))) 9163855Smarkm return EPERM; 9263855Smarkm else 9363855Smarkm return 0; 9463855Smarkm} 9563855Smarkm 9663855Smarkmstatic int 9769172Smarkmrandom_close(dev_t dev, int flags, int fmt, struct proc *p) 9869172Smarkm{ 9969174Smarkm if ((flags & FWRITE) && !(securelevel > 0 || suser(p))) 10069172Smarkm random_reseed(); 10169172Smarkm return 0; 10269172Smarkm} 10369172Smarkm 10469172Smarkmstatic int 10562765Smarkmrandom_read(dev_t dev, struct uio *uio, int flag) 10662053Smarkm{ 10762053Smarkm u_int c, ret; 10862053Smarkm int error = 0; 10962840Smarkm void *random_buf; 11062053Smarkm 11167286Speter while (!random_state.seeded) { 11267286Speter if (flag & IO_NDELAY) 11367286Speter error = EWOULDBLOCK; 11467112Smarkm else 11567286Speter error = tsleep(&random_state, PUSER|PCATCH, "rndblk", 0); 11667286Speter if (error != 0) 11767286Speter return error; 11867112Smarkm } 11967286Speter c = min(uio->uio_resid, PAGE_SIZE); 12067286Speter random_buf = (void *)malloc(c, M_TEMP, M_WAITOK); 12167286Speter while (uio->uio_resid > 0 && error == 0) { 12267286Speter ret = read_random_real(random_buf, c); 12367286Speter error = uiomove(random_buf, ret, uio); 12467286Speter } 12567286Speter free(random_buf, M_TEMP); 12662053Smarkm return error; 12762053Smarkm} 12862053Smarkm 12962053Smarkmstatic int 13062765Smarkmrandom_write(dev_t dev, struct uio *uio, int flag) 13162053Smarkm{ 13262053Smarkm u_int c; 13362053Smarkm int error = 0; 13462840Smarkm void *random_buf; 13562053Smarkm 13662765Smarkm random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 13762053Smarkm while (uio->uio_resid > 0) { 13862053Smarkm c = min(uio->uio_resid, PAGE_SIZE); 13962765Smarkm error = uiomove(random_buf, c, uio); 14062053Smarkm if (error) 14162053Smarkm break; 14263306Smarkm write_random(random_buf, c); 14362053Smarkm } 14462765Smarkm free(random_buf, M_TEMP); 14562053Smarkm return error; 14662053Smarkm} 14762053Smarkm 14862053Smarkmstatic int 14965686Smarkmrandom_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 15065686Smarkm{ 15165686Smarkm return ENOTTY; 15265686Smarkm} 15365686Smarkm 15465686Smarkmstatic int 15567112Smarkmrandom_poll(dev_t dev, int events, struct proc *p) 15667112Smarkm{ 15767112Smarkm int revents; 15867112Smarkm 15967112Smarkm revents = 0; 16067112Smarkm if (events & (POLLIN | POLLRDNORM)) { 16167112Smarkm if (random_state.seeded) 16267112Smarkm revents = events & (POLLIN | POLLRDNORM); 16367112Smarkm else 16467112Smarkm selrecord(p, &random_state.rsel); 16567112Smarkm } 16667112Smarkm return revents; 16767112Smarkm} 16867112Smarkm 16967112Smarkmstatic int 17062053Smarkmrandom_modevent(module_t mod, int type, void *data) 17162053Smarkm{ 17271037Smarkm struct sysctl_oid *node_base, *node1, *node2; 17371037Smarkm int error, i; 17465686Smarkm 17562053Smarkm switch(type) { 17662053Smarkm case MOD_LOAD: 17765686Smarkm error = random_init(); 17865686Smarkm if (error != 0) 17965686Smarkm return error; 18071037Smarkm 18171037Smarkm random_sysctl[sysctlcount++] = node_base = 18271037Smarkm SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_kern), 18371037Smarkm OID_AUTO, "random", CTLFLAG_RW, 0, 18471037Smarkm "Random Number Generator"); 18571037Smarkm random_sysctl[sysctlcount++] = node1 = 18671037Smarkm SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(node_base), 18771037Smarkm OID_AUTO, "sys", CTLFLAG_RW, 0, 18871037Smarkm "Entropy Device Parameters"); 18971037Smarkm random_sysctl[sysctlcount++] = 19071037Smarkm SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node1), 19171037Smarkm OID_AUTO, "seeded", CTLFLAG_RW, 19271037Smarkm &random_state.seeded, 0, "Seeded State"); 19371037Smarkm random_sysctl[sysctlcount++] = node2 = 19471037Smarkm SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(node_base), 19571037Smarkm OID_AUTO, "yarrow", CTLFLAG_RW, 0, 19671037Smarkm "Yarrow Parameters"); 19771037Smarkm random_sysctl[sysctlcount++] = 19871037Smarkm SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node2), 19971037Smarkm OID_AUTO, "gengateinterval", CTLFLAG_RW, 20071037Smarkm &random_state.gengateinterval, 0, 20171037Smarkm "Generator Gate Interval"); 20271037Smarkm random_sysctl[sysctlcount++] = 20371037Smarkm SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node2), 20471037Smarkm OID_AUTO, "bins", CTLFLAG_RW, 20571037Smarkm &random_state.bins, 0, 20671037Smarkm "Execution time tuner"); 20771037Smarkm random_sysctl[sysctlcount++] = 20871037Smarkm SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node2), 20971037Smarkm OID_AUTO, "fastthresh", CTLFLAG_RW, 21071037Smarkm &random_state.pool[0].thresh, 0, 21171037Smarkm "Fast pool reseed threshhold"); 21271037Smarkm random_sysctl[sysctlcount++] = 21371037Smarkm SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node2), 21471037Smarkm OID_AUTO, "slowthresh", CTLFLAG_RW, 21571037Smarkm &random_state.pool[1].thresh, 0, 21671037Smarkm "Slow pool reseed threshhold"); 21771037Smarkm random_sysctl[sysctlcount++] = 21871037Smarkm SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node2), 21971037Smarkm OID_AUTO, "slowoverthresh", CTLFLAG_RW, 22071037Smarkm &random_state.slowoverthresh, 0, 22171037Smarkm "Slow pool over-threshhold reseed"); 22271037Smarkm 22362053Smarkm if (bootverbose) 22462053Smarkm printf("random: <entropy source>\n"); 22562765Smarkm random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, UID_ROOT, 22662149Smarkm GID_WHEEL, 0666, "random"); 22762765Smarkm urandom_dev = make_dev(&random_cdevsw, URANDOM_MINOR, UID_ROOT, 22865686Smarkm GID_WHEEL, 0666, "urandom"); /* XXX Temporary */ 22962053Smarkm return 0; 23062053Smarkm 23162053Smarkm case MOD_UNLOAD: 23262765Smarkm random_deinit(); 23362765Smarkm destroy_dev(random_dev); 23465686Smarkm destroy_dev(urandom_dev); /* XXX Temporary */ 23571037Smarkm for (i = sysctlcount - 1; i >= 0; i--) 23671037Smarkm if (sysctl_remove_oid(random_sysctl[i], 1, 0) == EINVAL) 23771037Smarkm panic("random: removing sysctl"); 23862053Smarkm return 0; 23962053Smarkm 24062053Smarkm case MOD_SHUTDOWN: 24162053Smarkm return 0; 24262053Smarkm 24362053Smarkm default: 24462053Smarkm return EOPNOTSUPP; 24562053Smarkm } 24662053Smarkm} 24762053Smarkm 24862053SmarkmDEV_MODULE(random, random_modevent, NULL); 249