randomdev.c revision 128321
1254885Sdumbbell/*- 2254885Sdumbbell * Copyright (c) 2000-2004 Mark R V Murray 3254885Sdumbbell * All rights reserved. 4254885Sdumbbell * 5254885Sdumbbell * Redistribution and use in source and binary forms, with or without 6254885Sdumbbell * modification, are permitted provided that the following conditions 7254885Sdumbbell * are met: 8254885Sdumbbell * 1. Redistributions of source code must retain the above copyright 9254885Sdumbbell * notice, this list of conditions and the following disclaimer 10254885Sdumbbell * in this position and unchanged. 11254885Sdumbbell * 2. Redistributions in binary form must reproduce the above copyright 12254885Sdumbbell * notice, this list of conditions and the following disclaimer in the 13254885Sdumbbell * documentation and/or other materials provided with the distribution. 14254885Sdumbbell * 15254885Sdumbbell * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16254885Sdumbbell * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17254885Sdumbbell * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18254885Sdumbbell * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19254885Sdumbbell * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20254885Sdumbbell * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21254885Sdumbbell * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22254885Sdumbbell * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23254885Sdumbbell * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24254885Sdumbbell * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25254885Sdumbbell * 26254885Sdumbbell */ 27254885Sdumbbell 28254885Sdumbbell#include <sys/cdefs.h> 29254885Sdumbbell__FBSDID("$FreeBSD: head/sys/dev/random/randomdev.c 128321 2004-04-16 17:10:54Z markm $"); 30254885Sdumbbell 31254885Sdumbbell#include <sys/param.h> 32254885Sdumbbell#include <sys/systm.h> 33254885Sdumbbell#include <sys/bus.h> 34254885Sdumbbell#include <sys/conf.h> 35254885Sdumbbell#include <sys/fcntl.h> 36254885Sdumbbell#include <sys/filio.h> 37254885Sdumbbell#include <sys/kernel.h> 38254885Sdumbbell#include <sys/kthread.h> 39254885Sdumbbell#include <sys/lock.h> 40254885Sdumbbell#include <sys/malloc.h> 41254885Sdumbbell#include <sys/mutex.h> 42254885Sdumbbell#include <sys/poll.h> 43254885Sdumbbell#include <sys/proc.h> 44254885Sdumbbell#include <sys/selinfo.h> 45254885Sdumbbell#include <sys/uio.h> 46254885Sdumbbell#include <sys/unistd.h> 47254885Sdumbbell#include <sys/vnode.h> 48254885Sdumbbell 49254885Sdumbbell#include <machine/bus.h> 50254885Sdumbbell#include <machine/cpu.h> 51254885Sdumbbell 52254885Sdumbbell#include <dev/random/randomdev.h> 53254885Sdumbbell 54254885Sdumbbell#define RANDOM_MINOR 0 55254885Sdumbbell 56254885Sdumbbellstatic d_close_t random_close; 57254885Sdumbbellstatic d_read_t random_read; 58254885Sdumbbellstatic d_write_t random_write; 59254885Sdumbbellstatic d_ioctl_t random_ioctl; 60254885Sdumbbellstatic d_poll_t random_poll; 61254885Sdumbbell 62254885Sdumbbellstatic struct cdevsw random_cdevsw = { 63254885Sdumbbell .d_version = D_VERSION, 64254885Sdumbbell .d_flags = D_NEEDGIANT, 65254885Sdumbbell .d_close = random_close, 66254885Sdumbbell .d_read = random_read, 67254885Sdumbbell .d_write = random_write, 68254885Sdumbbell .d_ioctl = random_ioctl, 69254885Sdumbbell .d_poll = random_poll, 70254885Sdumbbell .d_name = "random", 71254885Sdumbbell}; 72254885Sdumbbell 73254885Sdumbbellstatic void *random_buf; 74254885Sdumbbell 75254885Sdumbbellstruct random_systat random_systat; 76254885Sdumbbell 77254885Sdumbbell/* For use with make_dev(9)/destroy_dev(9). */ 78254885Sdumbbellstatic dev_t random_dev; 79254885Sdumbbell 80254885Sdumbbell/* Used to fake out unused random calls in random_systat */ 81254885Sdumbbellvoid 82254885Sdumbbellrandom_null_func(void) 83254885Sdumbbell{ 84254885Sdumbbell} 85254885Sdumbbell 86254885Sdumbbell/* ARGSUSED */ 87254885Sdumbbellstatic int 88254885Sdumbbellrandom_close(dev_t dev __unused, int flags, int fmt __unused, 89254885Sdumbbell struct thread *td) 90254885Sdumbbell{ 91254885Sdumbbell if ((flags & FWRITE) && (suser(td) == 0) 92254885Sdumbbell && (securelevel_gt(td->td_ucred, 0) == 0)) { 93254885Sdumbbell (*random_systat.reseed)(); 94254885Sdumbbell random_systat.seeded = 1; 95254885Sdumbbell } 96254885Sdumbbell 97254885Sdumbbell return (0); 98254885Sdumbbell} 99254885Sdumbbell 100254885Sdumbbell/* ARGSUSED */ 101254885Sdumbbellstatic int 102254885Sdumbbellrandom_read(dev_t dev __unused, struct uio *uio, int flag) 103254885Sdumbbell{ 104254885Sdumbbell int c, error = 0; 105254885Sdumbbell 106254885Sdumbbell /* Blocking logic */ 107254885Sdumbbell while (!random_systat.seeded && !error) { 108254885Sdumbbell if (flag & IO_NDELAY) 109254885Sdumbbell error = EWOULDBLOCK; 110254885Sdumbbell else { 111254885Sdumbbell /* No complaints please. This is temporary! */ 112254885Sdumbbell printf("Entropy device is blocking. " 113254885Sdumbbell "Dance fandango on keyboard to unblock.\n"); 114254885Sdumbbell error = tsleep(&random_systat, 115254885Sdumbbell PUSER | PCATCH, "block", 0); 116254885Sdumbbell } 117254885Sdumbbell } 118254885Sdumbbell 119254885Sdumbbell /* The actual read */ 120254885Sdumbbell if (!error) { 121254885Sdumbbell while (uio->uio_resid > 0 && !error) { 122254885Sdumbbell c = MIN(uio->uio_resid, PAGE_SIZE); 123254885Sdumbbell c = (*random_systat.read)(random_buf, c); 124254885Sdumbbell error = uiomove(random_buf, c, uio); 125254885Sdumbbell } 126254885Sdumbbell } 127254885Sdumbbell 128254885Sdumbbell return (error); 129254885Sdumbbell} 130254885Sdumbbell 131254885Sdumbbell/* ARGSUSED */ 132254885Sdumbbellstatic int 133254885Sdumbbellrandom_write(dev_t dev __unused, struct uio *uio, int flag __unused) 134254885Sdumbbell{ 135254885Sdumbbell int c, error = 0; 136254885Sdumbbell 137254885Sdumbbell while (uio->uio_resid > 0) { 138254885Sdumbbell c = MIN((int)uio->uio_resid, PAGE_SIZE); 139254885Sdumbbell error = uiomove(random_buf, c, uio); 140254885Sdumbbell if (error) 141254885Sdumbbell break; 142254885Sdumbbell (*random_systat.write)(random_buf, c); 143254885Sdumbbell } 144254885Sdumbbell 145254885Sdumbbell return (error); 146254885Sdumbbell} 147254885Sdumbbell 148254885Sdumbbell/* ARGSUSED */ 149254885Sdumbbellstatic int 150254885Sdumbbellrandom_ioctl(dev_t dev __unused, u_long cmd, caddr_t addr __unused, 151254885Sdumbbell int flags __unused, struct thread *td __unused) 152254885Sdumbbell{ 153254885Sdumbbell int error = 0; 154254885Sdumbbell 155254885Sdumbbell switch (cmd) { 156254885Sdumbbell /* Really handled in upper layer */ 157254885Sdumbbell case FIOASYNC: 158254885Sdumbbell case FIONBIO: 159254885Sdumbbell break; 160254885Sdumbbell default: 161254885Sdumbbell error = ENOTTY; 162254885Sdumbbell } 163254885Sdumbbell return (error); 164254885Sdumbbell} 165254885Sdumbbell 166254885Sdumbbell/* ARGSUSED */ 167254885Sdumbbellstatic int 168254885Sdumbbellrandom_poll(dev_t dev __unused, int events, struct thread *td) 169254885Sdumbbell{ 170254885Sdumbbell int revents = 0; 171254885Sdumbbell 172254885Sdumbbell if (events & (POLLIN | POLLRDNORM)) { 173254885Sdumbbell if (random_systat.seeded) 174254885Sdumbbell revents = events & (POLLIN | POLLRDNORM); 175254885Sdumbbell else 176254885Sdumbbell selrecord(td, &random_systat.rsel); 177254885Sdumbbell } 178254885Sdumbbell return (revents); 179254885Sdumbbell} 180254885Sdumbbell 181254885Sdumbbell/* ARGSUSED */ 182254885Sdumbbellstatic int 183254885Sdumbbellrandom_modevent(module_t mod __unused, int type, void *data __unused) 184254885Sdumbbell{ 185254885Sdumbbell int error = 0; 186254885Sdumbbell 187254885Sdumbbell switch (type) { 188254885Sdumbbell case MOD_LOAD: 189254885Sdumbbell random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 190254885Sdumbbell random_ident_hardware(&random_systat); 191254885Sdumbbell (*random_systat.init)(); 192254885Sdumbbell 193254885Sdumbbell printf("random: <entropy source, %s>\n", random_systat.ident); 194254885Sdumbbell 195254885Sdumbbell random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, 196254885Sdumbbell UID_ROOT, GID_WHEEL, 0666, "random"); 197254885Sdumbbell make_dev_alias(random_dev, "urandom"); /* XXX Deprecated */ 198254885Sdumbbell 199254885Sdumbbell break; 200254885Sdumbbell 201254885Sdumbbell case MOD_UNLOAD: 202254885Sdumbbell (*random_systat.deinit)(); 203254885Sdumbbell free(random_buf, M_TEMP); 204254885Sdumbbell 205254885Sdumbbell destroy_dev(random_dev); 206254885Sdumbbell 207254885Sdumbbell break; 208254885Sdumbbell 209254885Sdumbbell case MOD_SHUTDOWN: 210254885Sdumbbell break; 211254885Sdumbbell 212254885Sdumbbell } 213254885Sdumbbell return (error); 214254885Sdumbbell} 215254885Sdumbbell 216254885SdumbbellDEV_MODULE(random, random_modevent, NULL); 217254885Sdumbbell