14db9ae91SMark Murray /*- 2f02e47dcSMark Murray * Copyright (c) 2000-2013 Mark R V Murray 35711939bSDavid E. O'Brien * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> 44db9ae91SMark Murray * All rights reserved. 54db9ae91SMark Murray * 64db9ae91SMark Murray * Redistribution and use in source and binary forms, with or without 74db9ae91SMark Murray * modification, are permitted provided that the following conditions 84db9ae91SMark Murray * are met: 94db9ae91SMark Murray * 1. Redistributions of source code must retain the above copyright 104db9ae91SMark Murray * notice, this list of conditions and the following disclaimer 114db9ae91SMark Murray * in this position and unchanged. 124db9ae91SMark Murray * 2. Redistributions in binary form must reproduce the above copyright 134db9ae91SMark Murray * notice, this list of conditions and the following disclaimer in the 144db9ae91SMark Murray * documentation and/or other materials provided with the distribution. 154db9ae91SMark Murray * 164db9ae91SMark Murray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 174db9ae91SMark Murray * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 184db9ae91SMark Murray * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 194db9ae91SMark Murray * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 204db9ae91SMark Murray * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 214db9ae91SMark Murray * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 224db9ae91SMark Murray * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 234db9ae91SMark Murray * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 244db9ae91SMark Murray * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 254db9ae91SMark Murray * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 264db9ae91SMark Murray * 274db9ae91SMark Murray */ 284db9ae91SMark Murray 29aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 30aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 31aad970f1SDavid E. O'Brien 324db9ae91SMark Murray #include <sys/param.h> 334db9ae91SMark Murray #include <sys/systm.h> 34fb919e4dSMark Murray #include <sys/bus.h> 354db9ae91SMark Murray #include <sys/conf.h> 364db9ae91SMark Murray #include <sys/fcntl.h> 37fb919e4dSMark Murray #include <sys/filio.h> 384db9ae91SMark Murray #include <sys/kernel.h> 3902c986abSMark Murray #include <sys/kthread.h> 40fb919e4dSMark Murray #include <sys/lock.h> 414db9ae91SMark Murray #include <sys/malloc.h> 4241ee9f1cSPoul-Henning Kamp #include <sys/module.h> 43fb919e4dSMark Murray #include <sys/mutex.h> 44a6278a2aSMark Murray #include <sys/poll.h> 45acd3428bSRobert Watson #include <sys/priv.h> 46b40ce416SJulian Elischer #include <sys/proc.h> 47f02e47dcSMark Murray #include <sys/random.h> 48fb919e4dSMark Murray #include <sys/selinfo.h> 49fb919e4dSMark Murray #include <sys/uio.h> 5002c986abSMark Murray #include <sys/unistd.h> 514db9ae91SMark Murray 5202c986abSMark Murray #include <machine/bus.h> 5302c986abSMark Murray #include <machine/cpu.h> 5402c986abSMark Murray 5502c986abSMark Murray #include <dev/random/randomdev.h> 56*095ed2c9SMark Murray #include <dev/random/randomdev_soft.h> 57*095ed2c9SMark Murray #include <dev/random/random_adaptors.h> 58*095ed2c9SMark Murray #include <dev/random/random_harvestq.h> 59*095ed2c9SMark Murray #include <dev/random/live_entropy_sources.h> 604db9ae91SMark Murray 61e7806b4cSMark Murray #define RANDOM_MINOR 0 62e7806b4cSMark Murray 63c9ec235cSMark Murray static d_read_t random_read; 64c9ec235cSMark Murray static d_write_t random_write; 654d87a031SMark Murray static d_ioctl_t random_ioctl; 66a6278a2aSMark Murray static d_poll_t random_poll; 674db9ae91SMark Murray 684db9ae91SMark Murray static struct cdevsw random_cdevsw = { 69dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 707ac40f5fSPoul-Henning Kamp .d_read = random_read, 717ac40f5fSPoul-Henning Kamp .d_write = random_write, 727ac40f5fSPoul-Henning Kamp .d_ioctl = random_ioctl, 737ac40f5fSPoul-Henning Kamp .d_poll = random_poll, 747ac40f5fSPoul-Henning Kamp .d_name = "random", 754db9ae91SMark Murray }; 764db9ae91SMark Murray 77*095ed2c9SMark Murray MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers"); 78*095ed2c9SMark Murray 794db9ae91SMark Murray /* For use with make_dev(9)/destroy_dev(9). */ 8089c9c53dSPoul-Henning Kamp static struct cdev *random_dev; 814db9ae91SMark Murray 82e1199601SMark Murray /* ARGSUSED */ 8350636159SMark Murray static int 8489c9c53dSPoul-Henning Kamp random_read(struct cdev *dev __unused, struct uio *uio, int flag) 854db9ae91SMark Murray { 86e7806b4cSMark Murray int c, error = 0; 87fa2d865bSMark Murray void *random_buf; 884db9ae91SMark Murray 89e7806b4cSMark Murray /* Blocking logic */ 905711939bSDavid E. O'Brien if (!random_adaptor->seeded) 915711939bSDavid E. O'Brien error = (*random_adaptor->block)(flag); 92e7806b4cSMark Murray 93e7806b4cSMark Murray /* The actual read */ 94e7806b4cSMark Murray if (!error) { 95fa2d865bSMark Murray 96*095ed2c9SMark Murray random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); 97fa2d865bSMark Murray 98e7806b4cSMark Murray while (uio->uio_resid > 0 && !error) { 99e7806b4cSMark Murray c = MIN(uio->uio_resid, PAGE_SIZE); 1005711939bSDavid E. O'Brien c = (*random_adaptor->read)(random_buf, c); 101e7806b4cSMark Murray error = uiomove(random_buf, c, uio); 1024db9ae91SMark Murray } 103f02e47dcSMark Murray /* Finished reading; let the source know so it can do some 104f02e47dcSMark Murray * optional housekeeping */ 105f02e47dcSMark Murray (*random_adaptor->read)(NULL, 0); 106fa2d865bSMark Murray 107*095ed2c9SMark Murray free(random_buf, M_ENTROPY); 108fa2d865bSMark Murray 109e7806b4cSMark Murray } 110f587c6bfSMark Murray 111e7806b4cSMark Murray return (error); 1124db9ae91SMark Murray } 1134db9ae91SMark Murray 114e1199601SMark Murray /* ARGSUSED */ 1154db9ae91SMark Murray static int 11689c9c53dSPoul-Henning Kamp random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused) 1174db9ae91SMark Murray { 118fa2d865bSMark Murray 119f02e47dcSMark Murray /* We used to allow this to insert userland entropy. 120f02e47dcSMark Murray * We don't any more because (1) this so-called entropy 121f02e47dcSMark Murray * is usually lousy and (b) its vaguely possible to 122f02e47dcSMark Murray * mess with entropy harvesting by overdoing a write. 123f02e47dcSMark Murray * Now we just ignore input like /dev/null does. 124f02e47dcSMark Murray */ 125f02e47dcSMark Murray uio->uio_resid = 0; 1264db9ae91SMark Murray 127f02e47dcSMark Murray return (0); 1284db9ae91SMark Murray } 1294db9ae91SMark Murray 130e1199601SMark Murray /* ARGSUSED */ 1314db9ae91SMark Murray static int 13289c9c53dSPoul-Henning Kamp random_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, 133e1199601SMark Murray int flags __unused, struct thread *td __unused) 1344d87a031SMark Murray { 135e7806b4cSMark Murray int error = 0; 136e7806b4cSMark Murray 13741bc9751SMark Murray switch (cmd) { 13841bc9751SMark Murray /* Really handled in upper layer */ 13941bc9751SMark Murray case FIOASYNC: 14041bc9751SMark Murray case FIONBIO: 141e7806b4cSMark Murray break; 14241bc9751SMark Murray default: 143e7806b4cSMark Murray error = ENOTTY; 1444d87a031SMark Murray } 145e7806b4cSMark Murray return (error); 14641bc9751SMark Murray } 1474d87a031SMark Murray 148e1199601SMark Murray /* ARGSUSED */ 1494d87a031SMark Murray static int 15089c9c53dSPoul-Henning Kamp random_poll(struct cdev *dev __unused, int events, struct thread *td) 151a6278a2aSMark Murray { 152e7806b4cSMark Murray int revents = 0; 153a6278a2aSMark Murray 154a6278a2aSMark Murray if (events & (POLLIN | POLLRDNORM)) { 1555711939bSDavid E. O'Brien if (random_adaptor->seeded) 156a6278a2aSMark Murray revents = events & (POLLIN | POLLRDNORM); 157a6278a2aSMark Murray else 1585711939bSDavid E. O'Brien revents = (*random_adaptor->poll)(events, td); 159a6278a2aSMark Murray } 160e7806b4cSMark Murray return (revents); 161a6278a2aSMark Murray } 162a6278a2aSMark Murray 1635711939bSDavid E. O'Brien static void 1645711939bSDavid E. O'Brien random_initialize(void *p, struct random_adaptor *s) 1655711939bSDavid E. O'Brien { 166f02e47dcSMark Murray static int random_inited = 0; 167f02e47dcSMark Murray 1685711939bSDavid E. O'Brien if (random_inited) { 1695711939bSDavid E. O'Brien printf("random: <%s> already initialized\n", 1705711939bSDavid E. O'Brien random_adaptor->ident); 1715711939bSDavid E. O'Brien return; 1725711939bSDavid E. O'Brien } 1735711939bSDavid E. O'Brien 1745711939bSDavid E. O'Brien random_adaptor = s; 1755711939bSDavid E. O'Brien 1765711939bSDavid E. O'Brien (s->init)(); 1775711939bSDavid E. O'Brien 1785711939bSDavid E. O'Brien printf("random: <%s> initialized\n", s->ident); 1795711939bSDavid E. O'Brien 180f02e47dcSMark Murray /* Use an appropriately evil mode for those who are concerned 181f02e47dcSMark Murray * with daemons */ 1825711939bSDavid E. O'Brien random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, 1835711939bSDavid E. O'Brien RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random"); 1845711939bSDavid E. O'Brien 1855711939bSDavid E. O'Brien /* mark random(4) as initialized, to avoid being called again */ 1865711939bSDavid E. O'Brien random_inited = 1; 1875711939bSDavid E. O'Brien } 1885711939bSDavid E. O'Brien 189e1199601SMark Murray /* ARGSUSED */ 190a6278a2aSMark Murray static int 191e1199601SMark Murray random_modevent(module_t mod __unused, int type, void *data __unused) 1924db9ae91SMark Murray { 193f02e47dcSMark Murray static eventhandler_tag attach_tag = NULL; 194e7806b4cSMark Murray int error = 0; 1954d87a031SMark Murray 1964db9ae91SMark Murray switch (type) { 1974db9ae91SMark Murray case MOD_LOAD: 198ddbfa6b1SMark Murray random_adaptor_choose(&random_adaptor); 199b79ad7e6SMark Murray 2005711939bSDavid E. O'Brien if (random_adaptor == NULL) { 201f02e47dcSMark Murray printf("random: No random adaptor attached, " 202f02e47dcSMark Murray "postponing initialization\n"); 2035711939bSDavid E. O'Brien attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach, 2045711939bSDavid E. O'Brien random_initialize, NULL, EVENTHANDLER_PRI_ANY); 205f02e47dcSMark Murray } else 2065711939bSDavid E. O'Brien random_initialize(NULL, random_adaptor); 207b79ad7e6SMark Murray 208e7806b4cSMark Murray break; 2094db9ae91SMark Murray 2104db9ae91SMark Murray case MOD_UNLOAD: 2115711939bSDavid E. O'Brien if (random_adaptor != NULL) { 2125711939bSDavid E. O'Brien (*random_adaptor->deinit)(); 213c9ec235cSMark Murray destroy_dev(random_dev); 2145711939bSDavid E. O'Brien } 2155711939bSDavid E. O'Brien /* Unregister the event handler */ 216f02e47dcSMark Murray if (attach_tag != NULL) 2175711939bSDavid E. O'Brien EVENTHANDLER_DEREGISTER(random_adaptor_attach, 2185711939bSDavid E. O'Brien attach_tag); 219e7806b4cSMark Murray 220e7806b4cSMark Murray break; 2214db9ae91SMark Murray 2224db9ae91SMark Murray case MOD_SHUTDOWN: 223e7806b4cSMark Murray break; 2244db9ae91SMark Murray 2253e019deaSPoul-Henning Kamp default: 2263e019deaSPoul-Henning Kamp error = EOPNOTSUPP; 2273e019deaSPoul-Henning Kamp break; 2283e019deaSPoul-Henning Kamp 2294db9ae91SMark Murray } 230e7806b4cSMark Murray return (error); 2314db9ae91SMark Murray } 2324db9ae91SMark Murray 2334db9ae91SMark Murray DEV_MODULE(random, random_modevent, NULL); 234ce46e205SMark Murray MODULE_VERSION(random, 1); 235