14db9ae91SMark Murray /*- 2e7806b4cSMark Murray * Copyright (c) 2000-2004 Mark R V Murray 34db9ae91SMark Murray * All rights reserved. 44db9ae91SMark Murray * 54db9ae91SMark Murray * Redistribution and use in source and binary forms, with or without 64db9ae91SMark Murray * modification, are permitted provided that the following conditions 74db9ae91SMark Murray * are met: 84db9ae91SMark Murray * 1. Redistributions of source code must retain the above copyright 94db9ae91SMark Murray * notice, this list of conditions and the following disclaimer 104db9ae91SMark Murray * in this position and unchanged. 114db9ae91SMark Murray * 2. Redistributions in binary form must reproduce the above copyright 124db9ae91SMark Murray * notice, this list of conditions and the following disclaimer in the 134db9ae91SMark Murray * documentation and/or other materials provided with the distribution. 144db9ae91SMark Murray * 154db9ae91SMark Murray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 164db9ae91SMark Murray * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 174db9ae91SMark Murray * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 184db9ae91SMark Murray * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 194db9ae91SMark Murray * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 204db9ae91SMark Murray * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 214db9ae91SMark Murray * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 224db9ae91SMark Murray * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 234db9ae91SMark Murray * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 244db9ae91SMark Murray * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 254db9ae91SMark Murray * 264db9ae91SMark Murray */ 274db9ae91SMark Murray 28aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 29aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 30aad970f1SDavid E. O'Brien 314db9ae91SMark Murray #include <sys/param.h> 324db9ae91SMark Murray #include <sys/systm.h> 33fb919e4dSMark Murray #include <sys/bus.h> 344db9ae91SMark Murray #include <sys/conf.h> 354db9ae91SMark Murray #include <sys/fcntl.h> 36fb919e4dSMark Murray #include <sys/filio.h> 374db9ae91SMark Murray #include <sys/kernel.h> 3802c986abSMark Murray #include <sys/kthread.h> 39fb919e4dSMark Murray #include <sys/lock.h> 404db9ae91SMark Murray #include <sys/malloc.h> 4141ee9f1cSPoul-Henning Kamp #include <sys/module.h> 42fb919e4dSMark Murray #include <sys/mutex.h> 43a6278a2aSMark Murray #include <sys/poll.h> 44b40ce416SJulian Elischer #include <sys/proc.h> 45fb919e4dSMark Murray #include <sys/selinfo.h> 46fb919e4dSMark Murray #include <sys/uio.h> 4702c986abSMark Murray #include <sys/unistd.h> 48fb919e4dSMark Murray #include <sys/vnode.h> 494db9ae91SMark Murray 5002c986abSMark Murray #include <machine/bus.h> 5102c986abSMark Murray #include <machine/cpu.h> 5202c986abSMark Murray 5302c986abSMark Murray #include <dev/random/randomdev.h> 544db9ae91SMark Murray 55e7806b4cSMark Murray #define RANDOM_MINOR 0 56e7806b4cSMark Murray 5750636159SMark Murray static d_close_t random_close; 58c9ec235cSMark Murray static d_read_t random_read; 59c9ec235cSMark Murray static d_write_t random_write; 604d87a031SMark Murray static d_ioctl_t random_ioctl; 61a6278a2aSMark Murray static d_poll_t random_poll; 624db9ae91SMark Murray 634db9ae91SMark Murray static struct cdevsw random_cdevsw = { 64dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 6555636152SMark Murray .d_flags = D_NEEDGIANT, 667ac40f5fSPoul-Henning Kamp .d_close = random_close, 677ac40f5fSPoul-Henning Kamp .d_read = random_read, 687ac40f5fSPoul-Henning Kamp .d_write = random_write, 697ac40f5fSPoul-Henning Kamp .d_ioctl = random_ioctl, 707ac40f5fSPoul-Henning Kamp .d_poll = random_poll, 717ac40f5fSPoul-Henning Kamp .d_name = "random", 724db9ae91SMark Murray }; 734db9ae91SMark Murray 74e7806b4cSMark Murray struct random_systat random_systat; 7502c986abSMark Murray 764db9ae91SMark Murray /* For use with make_dev(9)/destroy_dev(9). */ 77c9ec235cSMark Murray static dev_t random_dev; 784db9ae91SMark Murray 79e7806b4cSMark Murray /* Used to fake out unused random calls in random_systat */ 80e7806b4cSMark Murray void 81e7806b4cSMark Murray random_null_func(void) 8202c986abSMark Murray { 8302c986abSMark Murray } 8402c986abSMark Murray 85e1199601SMark Murray /* ARGSUSED */ 864db9ae91SMark Murray static int 87e7806b4cSMark Murray random_close(dev_t dev __unused, int flags, int fmt __unused, 88e7806b4cSMark Murray struct thread *td) 8950636159SMark Murray { 90e7806b4cSMark Murray if ((flags & FWRITE) && (suser(td) == 0) 91e7806b4cSMark Murray && (securelevel_gt(td->td_ucred, 0) == 0)) { 92e7806b4cSMark Murray (*random_systat.reseed)(); 93e7806b4cSMark Murray random_systat.seeded = 1; 9419f15659SRobert Watson } 9555636152SMark Murray 96e7806b4cSMark Murray return (0); 9750636159SMark Murray } 9850636159SMark Murray 99e1199601SMark Murray /* ARGSUSED */ 10050636159SMark Murray static int 101e1199601SMark Murray random_read(dev_t dev __unused, struct uio *uio, int flag) 1024db9ae91SMark Murray { 103e7806b4cSMark Murray int c, error = 0; 104fa2d865bSMark Murray void *random_buf; 1054db9ae91SMark Murray 106e7806b4cSMark Murray /* Blocking logic */ 107e7806b4cSMark Murray while (!random_systat.seeded && !error) { 10893d88e00SPeter Wemm if (flag & IO_NDELAY) 109a6278a2aSMark Murray error = EWOULDBLOCK; 11055636152SMark Murray else { 11155636152SMark Murray /* No complaints please. This is temporary! */ 11255636152SMark Murray printf("Entropy device is blocking. " 11355636152SMark Murray "Dance fandango on keyboard to unblock.\n"); 11455636152SMark Murray error = tsleep(&random_systat, 115e7806b4cSMark Murray PUSER | PCATCH, "block", 0); 116a6278a2aSMark Murray } 11755636152SMark Murray } 118e7806b4cSMark Murray 119e7806b4cSMark Murray /* The actual read */ 120e7806b4cSMark Murray if (!error) { 121fa2d865bSMark Murray 122fa2d865bSMark Murray random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 123fa2d865bSMark Murray 124e7806b4cSMark Murray while (uio->uio_resid > 0 && !error) { 125e7806b4cSMark Murray c = MIN(uio->uio_resid, PAGE_SIZE); 126e7806b4cSMark Murray c = (*random_systat.read)(random_buf, c); 127e7806b4cSMark Murray error = uiomove(random_buf, c, uio); 1284db9ae91SMark Murray } 129fa2d865bSMark Murray 130fa2d865bSMark Murray free(random_buf, M_TEMP); 131fa2d865bSMark Murray 132e7806b4cSMark Murray } 133f587c6bfSMark Murray 134e7806b4cSMark Murray return (error); 1354db9ae91SMark Murray } 1364db9ae91SMark Murray 137e1199601SMark Murray /* ARGSUSED */ 1384db9ae91SMark Murray static int 139e1199601SMark Murray random_write(dev_t dev __unused, struct uio *uio, int flag __unused) 1404db9ae91SMark Murray { 141e7806b4cSMark Murray int c, error = 0; 142fa2d865bSMark Murray void *random_buf; 143fa2d865bSMark Murray 144fa2d865bSMark Murray random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 1454db9ae91SMark Murray 1464db9ae91SMark Murray while (uio->uio_resid > 0) { 147e7806b4cSMark Murray c = MIN((int)uio->uio_resid, PAGE_SIZE); 148c9ec235cSMark Murray error = uiomove(random_buf, c, uio); 1494db9ae91SMark Murray if (error) 1504db9ae91SMark Murray break; 151e7806b4cSMark Murray (*random_systat.write)(random_buf, c); 1524db9ae91SMark Murray } 15355636152SMark Murray 154fa2d865bSMark Murray free(random_buf, M_TEMP); 155fa2d865bSMark Murray 156e7806b4cSMark Murray return (error); 1574db9ae91SMark Murray } 1584db9ae91SMark Murray 159e1199601SMark Murray /* ARGSUSED */ 1604db9ae91SMark Murray static int 161e1199601SMark Murray random_ioctl(dev_t dev __unused, u_long cmd, caddr_t addr __unused, 162e1199601SMark Murray int flags __unused, struct thread *td __unused) 1634d87a031SMark Murray { 164e7806b4cSMark Murray int error = 0; 165e7806b4cSMark Murray 16641bc9751SMark Murray switch (cmd) { 16741bc9751SMark Murray /* Really handled in upper layer */ 16841bc9751SMark Murray case FIOASYNC: 16941bc9751SMark Murray case FIONBIO: 170e7806b4cSMark Murray break; 17141bc9751SMark Murray default: 172e7806b4cSMark Murray error = ENOTTY; 1734d87a031SMark Murray } 174e7806b4cSMark Murray return (error); 17541bc9751SMark Murray } 1764d87a031SMark Murray 177e1199601SMark Murray /* ARGSUSED */ 1784d87a031SMark Murray static int 179e1199601SMark Murray random_poll(dev_t dev __unused, int events, struct thread *td) 180a6278a2aSMark Murray { 181e7806b4cSMark Murray int revents = 0; 182a6278a2aSMark Murray 183a6278a2aSMark Murray if (events & (POLLIN | POLLRDNORM)) { 18402c986abSMark Murray if (random_systat.seeded) 185a6278a2aSMark Murray revents = events & (POLLIN | POLLRDNORM); 186a6278a2aSMark Murray else 187ed01445dSJohn Baldwin selrecord(td, &random_systat.rsel); 188a6278a2aSMark Murray } 189e7806b4cSMark Murray return (revents); 190a6278a2aSMark Murray } 191a6278a2aSMark Murray 192e1199601SMark Murray /* ARGSUSED */ 193a6278a2aSMark Murray static int 194e1199601SMark Murray random_modevent(module_t mod __unused, int type, void *data __unused) 1954db9ae91SMark Murray { 196e7806b4cSMark Murray int error = 0; 1974d87a031SMark Murray 1984db9ae91SMark Murray switch (type) { 1994db9ae91SMark Murray case MOD_LOAD: 200e7806b4cSMark Murray random_ident_hardware(&random_systat); 201e7806b4cSMark Murray (*random_systat.init)(); 202b79ad7e6SMark Murray 203e7806b4cSMark Murray printf("random: <entropy source, %s>\n", random_systat.ident); 20402c986abSMark Murray 205e7806b4cSMark Murray random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, 206e7806b4cSMark Murray UID_ROOT, GID_WHEEL, 0666, "random"); 207e7806b4cSMark Murray make_dev_alias(random_dev, "urandom"); /* XXX Deprecated */ 208b79ad7e6SMark Murray 209e7806b4cSMark Murray break; 2104db9ae91SMark Murray 2114db9ae91SMark Murray case MOD_UNLOAD: 212e7806b4cSMark Murray (*random_systat.deinit)(); 21302c986abSMark Murray 214c9ec235cSMark Murray destroy_dev(random_dev); 215e7806b4cSMark Murray 216e7806b4cSMark Murray break; 2174db9ae91SMark Murray 2184db9ae91SMark Murray case MOD_SHUTDOWN: 219e7806b4cSMark Murray break; 2204db9ae91SMark Murray 2214db9ae91SMark Murray } 222e7806b4cSMark Murray return (error); 2234db9ae91SMark Murray } 2244db9ae91SMark Murray 2254db9ae91SMark Murray DEV_MODULE(random, random_modevent, NULL); 226