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