14db9ae91SMark Murray /*- 2*d1b06863SMark Murray * Copyright (c) 2000-2015 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> 4041ee9f1cSPoul-Henning Kamp #include <sys/module.h> 4110cb2424SMark Murray #include <sys/malloc.h> 42*d1b06863SMark Murray #include <sys/poll.h> 43b40ce416SJulian Elischer #include <sys/proc.h> 44f02e47dcSMark Murray #include <sys/random.h> 45*d1b06863SMark Murray #include <sys/sbuf.h> 46*d1b06863SMark Murray #include <sys/selinfo.h> 4710cb2424SMark Murray #include <sys/sysctl.h> 4810cb2424SMark Murray #include <sys/systm.h> 49fb919e4dSMark Murray #include <sys/uio.h> 5002c986abSMark Murray #include <sys/unistd.h> 514db9ae91SMark Murray 52*d1b06863SMark Murray #include <crypto/rijndael/rijndael-api-fst.h> 53*d1b06863SMark Murray #include <crypto/sha2/sha2.h> 54*d1b06863SMark Murray 55*d1b06863SMark Murray #include <dev/random/hash.h> 5602c986abSMark Murray #include <dev/random/randomdev.h> 57095ed2c9SMark Murray #include <dev/random/random_harvestq.h> 584db9ae91SMark Murray 59*d1b06863SMark Murray #include "opt_random.h" 60*d1b06863SMark Murray 61*d1b06863SMark Murray #if defined(RANDOM_DUMMY) && defined(RANDOM_YARROW) 62*d1b06863SMark Murray #error "Cannot define both RANDOM_DUMMY and RANDOM_YARROW" 63*d1b06863SMark Murray #endif 64*d1b06863SMark Murray 65e7806b4cSMark Murray #define RANDOM_MINOR 0 66e7806b4cSMark Murray 67*d1b06863SMark Murray static d_read_t randomdev_read; 68*d1b06863SMark Murray static d_write_t randomdev_write; 69*d1b06863SMark Murray static d_poll_t randomdev_poll; 7010cb2424SMark Murray static d_ioctl_t randomdev_ioctl; 714db9ae91SMark Murray 724db9ae91SMark Murray static struct cdevsw random_cdevsw = { 737ac40f5fSPoul-Henning Kamp .d_name = "random", 7410cb2424SMark Murray .d_version = D_VERSION, 75*d1b06863SMark Murray .d_read = randomdev_read, 76*d1b06863SMark Murray .d_write = randomdev_write, 77*d1b06863SMark Murray .d_poll = randomdev_poll, 7810cb2424SMark Murray .d_ioctl = randomdev_ioctl, 794db9ae91SMark Murray }; 804db9ae91SMark Murray 814db9ae91SMark Murray /* For use with make_dev(9)/destroy_dev(9). */ 8289c9c53dSPoul-Henning Kamp static struct cdev *random_dev; 834db9ae91SMark Murray 8410cb2424SMark Murray /* Set up the sysctl root node for the entropy device */ 85*d1b06863SMark Murray SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator"); 864db9ae91SMark Murray 8710cb2424SMark Murray MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); 884db9ae91SMark Murray 89*d1b06863SMark Murray #if defined(RANDOM_DUMMY) 90*d1b06863SMark Murray 91*d1b06863SMark Murray /*- 92*d1b06863SMark Murray * Dummy "always block" pseudo algorithm, used when there is no real 93*d1b06863SMark Murray * random(4) driver to provide a CSPRNG. 94*d1b06863SMark Murray */ 95*d1b06863SMark Murray 96*d1b06863SMark Murray static u_int 97*d1b06863SMark Murray dummy_random_zero(void) 98*d1b06863SMark Murray { 99*d1b06863SMark Murray 100*d1b06863SMark Murray return (0); 101*d1b06863SMark Murray } 102*d1b06863SMark Murray 103*d1b06863SMark Murray static void 104*d1b06863SMark Murray dummy_random(void) 105*d1b06863SMark Murray { 106*d1b06863SMark Murray } 107*d1b06863SMark Murray 108*d1b06863SMark Murray struct random_algorithm random_alg_context = { 109*d1b06863SMark Murray .ra_ident = "Dummy", 110*d1b06863SMark Murray .ra_reseed = dummy_random, 111*d1b06863SMark Murray .ra_seeded = (random_alg_seeded_t *)dummy_random_zero, 112*d1b06863SMark Murray .ra_pre_read = dummy_random, 113*d1b06863SMark Murray .ra_read = (random_alg_read_t *)dummy_random_zero, 114*d1b06863SMark Murray .ra_post_read = dummy_random, 115*d1b06863SMark Murray .ra_write = (random_alg_write_t *)dummy_random_zero, 116*d1b06863SMark Murray .ra_event_processor = NULL, 117*d1b06863SMark Murray .ra_poolcount = 0, 118*d1b06863SMark Murray }; 119*d1b06863SMark Murray 120*d1b06863SMark Murray #else /* !defined(RANDOM_DUMMY) */ 121*d1b06863SMark Murray 122*d1b06863SMark Murray LIST_HEAD(sources_head, random_sources); 123*d1b06863SMark Murray static struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list); 124*d1b06863SMark Murray static u_int read_rate; 125*d1b06863SMark Murray 126*d1b06863SMark Murray #endif /* defined(RANDOM_DUMMY) */ 127*d1b06863SMark Murray 128*d1b06863SMark Murray static struct selinfo rsel; 129*d1b06863SMark Murray 130*d1b06863SMark Murray /* 131*d1b06863SMark Murray * This is the read uio(9) interface for random(4). 132*d1b06863SMark Murray */ 133*d1b06863SMark Murray /* ARGSUSED */ 134*d1b06863SMark Murray static int 135*d1b06863SMark Murray randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags) 136*d1b06863SMark Murray { 137*d1b06863SMark Murray uint8_t *random_buf; 138*d1b06863SMark Murray int c, error; 139*d1b06863SMark Murray ssize_t nbytes; 140*d1b06863SMark Murray 141*d1b06863SMark Murray random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); 142*d1b06863SMark Murray random_alg_context.ra_pre_read(); 143*d1b06863SMark Murray /* (Un)Blocking logic */ 144*d1b06863SMark Murray error = 0; 145*d1b06863SMark Murray while (!random_alg_context.ra_seeded() && error == 0) { 146*d1b06863SMark Murray if (flags & O_NONBLOCK) { 147*d1b06863SMark Murray error = EWOULDBLOCK; 148*d1b06863SMark Murray break; 149*d1b06863SMark Murray } 150*d1b06863SMark Murray tsleep(&random_alg_context, 0, "randrd", hz/10); 151*d1b06863SMark Murray /* keep tapping away at the pre-read until we seed/unblock. */ 152*d1b06863SMark Murray random_alg_context.ra_pre_read(); 153*d1b06863SMark Murray printf("random: %s unblock (error = %d)\n", __func__, error); 154*d1b06863SMark Murray } 155*d1b06863SMark Murray if (error == 0) { 156*d1b06863SMark Murray #if !defined(RANDOM_DUMMY) 157*d1b06863SMark Murray /* XXX: FIX!! Next line as an atomic operation? */ 158*d1b06863SMark Murray read_rate += (uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t); 159*d1b06863SMark Murray #endif 160*d1b06863SMark Murray nbytes = uio->uio_resid; 161*d1b06863SMark Murray while (uio->uio_resid && !error) { 162*d1b06863SMark Murray c = MIN(uio->uio_resid, PAGE_SIZE); 163*d1b06863SMark Murray random_alg_context.ra_read(random_buf, c); 164*d1b06863SMark Murray error = uiomove(random_buf, c, uio); 165*d1b06863SMark Murray } 166*d1b06863SMark Murray random_alg_context.ra_post_read(); 167*d1b06863SMark Murray if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR) ) 168*d1b06863SMark Murray /* Return partial read, not error. */ 169*d1b06863SMark Murray error = 0; 170*d1b06863SMark Murray } 171*d1b06863SMark Murray free(random_buf, M_ENTROPY); 172*d1b06863SMark Murray return (error); 173*d1b06863SMark Murray } 174*d1b06863SMark Murray 175*d1b06863SMark Murray /*- 176*d1b06863SMark Murray * Kernel API version of read_random(). 177*d1b06863SMark Murray * This is similar to random_alg_read(), 178*d1b06863SMark Murray * except it doesn't interface with uio(9). 179*d1b06863SMark Murray * It cannot assumed that random_buf is a multiple of 180*d1b06863SMark Murray * RANDOM_BLOCKSIZE bytes. 181*d1b06863SMark Murray */ 182*d1b06863SMark Murray u_int 183*d1b06863SMark Murray read_random(void *random_buf, u_int len) 184*d1b06863SMark Murray { 185*d1b06863SMark Murray u_int read_len, total_read, c; 186*d1b06863SMark Murray uint8_t local_buf[len + RANDOM_BLOCKSIZE]; 187*d1b06863SMark Murray 188*d1b06863SMark Murray KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__)); 189*d1b06863SMark Murray random_alg_context.ra_pre_read(); 190*d1b06863SMark Murray /* (Un)Blocking logic; if not seeded, return nothing. */ 191*d1b06863SMark Murray if (random_alg_context.ra_seeded()) { 192*d1b06863SMark Murray #if !defined(RANDOM_DUMMY) 193*d1b06863SMark Murray /* XXX: FIX!! Next line as an atomic operation? */ 194*d1b06863SMark Murray read_rate += (len + sizeof(uint32_t))/sizeof(uint32_t); 195*d1b06863SMark Murray #endif 196*d1b06863SMark Murray read_len = len; 197*d1b06863SMark Murray total_read = 0; 198*d1b06863SMark Murray while (read_len) { 199*d1b06863SMark Murray c = MIN(read_len, PAGE_SIZE); 200*d1b06863SMark Murray random_alg_context.ra_read(&local_buf[total_read], c); 201*d1b06863SMark Murray read_len -= c; 202*d1b06863SMark Murray total_read += c; 203*d1b06863SMark Murray } 204*d1b06863SMark Murray memcpy(random_buf, local_buf, len); 205*d1b06863SMark Murray } else 206*d1b06863SMark Murray len = 0; 207*d1b06863SMark Murray random_alg_context.ra_post_read(); 208*d1b06863SMark Murray return (len); 209*d1b06863SMark Murray } 210*d1b06863SMark Murray 211*d1b06863SMark Murray /* ARGSUSED */ 212*d1b06863SMark Murray static int 213*d1b06863SMark Murray randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) 214*d1b06863SMark Murray { 215*d1b06863SMark Murray uint8_t *random_buf; 216*d1b06863SMark Murray int c, error = 0; 217*d1b06863SMark Murray ssize_t nbytes; 218*d1b06863SMark Murray 219*d1b06863SMark Murray random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); 220*d1b06863SMark Murray nbytes = uio->uio_resid; 221*d1b06863SMark Murray while (uio->uio_resid > 0 && error == 0) { 222*d1b06863SMark Murray c = MIN(uio->uio_resid, PAGE_SIZE); 223*d1b06863SMark Murray error = uiomove(random_buf, c, uio); 224*d1b06863SMark Murray if (error) 225*d1b06863SMark Murray break; 226*d1b06863SMark Murray random_alg_context.ra_write(random_buf, c); 227*d1b06863SMark Murray tsleep(&random_alg_context, 0, "randwr", hz/10); 228*d1b06863SMark Murray } 229*d1b06863SMark Murray if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR)) 230*d1b06863SMark Murray /* Partial write, not error. */ 231*d1b06863SMark Murray error = 0; 232*d1b06863SMark Murray free(random_buf, M_ENTROPY); 233*d1b06863SMark Murray return (error); 234*d1b06863SMark Murray } 235*d1b06863SMark Murray 236*d1b06863SMark Murray /* ARGSUSED */ 237*d1b06863SMark Murray static int 238*d1b06863SMark Murray randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 239*d1b06863SMark Murray { 240*d1b06863SMark Murray 241*d1b06863SMark Murray if (events & (POLLIN | POLLRDNORM)) { 242*d1b06863SMark Murray if (random_alg_context.ra_seeded()) 243*d1b06863SMark Murray events &= (POLLIN | POLLRDNORM); 244*d1b06863SMark Murray else 245*d1b06863SMark Murray selrecord(td, &rsel); 246*d1b06863SMark Murray } 247*d1b06863SMark Murray return (events); 248*d1b06863SMark Murray } 249*d1b06863SMark Murray 250*d1b06863SMark Murray /* This will be called by the entropy processor when it seeds itself and becomes secure */ 251*d1b06863SMark Murray void 252*d1b06863SMark Murray randomdev_unblock(void) 253*d1b06863SMark Murray { 254*d1b06863SMark Murray 255*d1b06863SMark Murray selwakeuppri(&rsel, PUSER); 256*d1b06863SMark Murray wakeup(&random_alg_context); 257*d1b06863SMark Murray printf("random: unblocking device.\n"); 258*d1b06863SMark Murray /* Do random(9) a favour while we are about it. */ 259*d1b06863SMark Murray (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE); 260*d1b06863SMark Murray } 261*d1b06863SMark Murray 262e1199601SMark Murray /* ARGSUSED */ 2634db9ae91SMark Murray static int 26410cb2424SMark Murray randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, 265e1199601SMark Murray int flags __unused, struct thread *td __unused) 2664d87a031SMark Murray { 267e7806b4cSMark Murray int error = 0; 268e7806b4cSMark Murray 26941bc9751SMark Murray switch (cmd) { 27041bc9751SMark Murray /* Really handled in upper layer */ 27141bc9751SMark Murray case FIOASYNC: 27241bc9751SMark Murray case FIONBIO: 273e7806b4cSMark Murray break; 27441bc9751SMark Murray default: 275e7806b4cSMark Murray error = ENOTTY; 2764d87a031SMark Murray } 27710cb2424SMark Murray 278e7806b4cSMark Murray return (error); 27941bc9751SMark Murray } 2804d87a031SMark Murray 281*d1b06863SMark Murray void 282*d1b06863SMark Murray random_source_register(struct random_source *rsource) 283*d1b06863SMark Murray { 284*d1b06863SMark Murray #if defined(RANDOM_DUMMY) 285*d1b06863SMark Murray (void)rsource; 286*d1b06863SMark Murray #else /* !defined(RANDOM_DUMMY) */ 287*d1b06863SMark Murray struct random_sources *rrs; 288*d1b06863SMark Murray 289*d1b06863SMark Murray KASSERT(rsource != NULL, ("invalid input to %s", __func__)); 290*d1b06863SMark Murray 291*d1b06863SMark Murray rrs = malloc(sizeof(*rrs), M_ENTROPY, M_WAITOK); 292*d1b06863SMark Murray rrs->rrs_source = rsource; 293*d1b06863SMark Murray 294*d1b06863SMark Murray printf("random: registering fast source %s\n", rsource->rs_ident); 295*d1b06863SMark Murray LIST_INSERT_HEAD(&source_list, rrs, rrs_entries); 296*d1b06863SMark Murray #endif /* defined(RANDOM_DUMMY) */ 297*d1b06863SMark Murray } 298*d1b06863SMark Murray 299*d1b06863SMark Murray void 300*d1b06863SMark Murray random_source_deregister(struct random_source *rsource) 301*d1b06863SMark Murray { 302*d1b06863SMark Murray #if defined(RANDOM_DUMMY) 303*d1b06863SMark Murray (void)rsource; 304*d1b06863SMark Murray #else /* !defined(RANDOM_DUMMY) */ 305*d1b06863SMark Murray struct random_sources *rrs = NULL; 306*d1b06863SMark Murray 307*d1b06863SMark Murray KASSERT(rsource != NULL, ("invalid input to %s", __func__)); 308*d1b06863SMark Murray LIST_FOREACH(rrs, &source_list, rrs_entries) 309*d1b06863SMark Murray if (rrs->rrs_source == rsource) { 310*d1b06863SMark Murray LIST_REMOVE(rrs, rrs_entries); 311*d1b06863SMark Murray break; 312*d1b06863SMark Murray } 313*d1b06863SMark Murray if (rrs != NULL) 314*d1b06863SMark Murray free(rrs, M_ENTROPY); 315*d1b06863SMark Murray #endif /* defined(RANDOM_DUMMY) */ 316*d1b06863SMark Murray } 317*d1b06863SMark Murray 318*d1b06863SMark Murray #if !defined(RANDOM_DUMMY) 319*d1b06863SMark Murray /* 320*d1b06863SMark Murray * Run through all fast sources reading entropy for the given 321*d1b06863SMark Murray * number of rounds, which should be a multiple of the number 322*d1b06863SMark Murray * of entropy accumulation pools in use; 2 for Yarrow and 32 323*d1b06863SMark Murray * for Fortuna. 324*d1b06863SMark Murray * 325*d1b06863SMark Murray * BEWARE!!! 326*d1b06863SMark Murray * This function runs inside the RNG thread! Don't do anything silly! 32710cb2424SMark Murray */ 32810cb2424SMark Murray void 329*d1b06863SMark Murray random_sources_feed(void) 330a6278a2aSMark Murray { 331*d1b06863SMark Murray uint32_t entropy[HARVESTSIZE]; 332*d1b06863SMark Murray struct random_sources *rrs; 333*d1b06863SMark Murray u_int i, n, local_read_rate; 334a6278a2aSMark Murray 335*d1b06863SMark Murray /* 336*d1b06863SMark Murray * Step over all of live entropy sources, and feed their output 337*d1b06863SMark Murray * to the system-wide RNG. 338*d1b06863SMark Murray */ 339*d1b06863SMark Murray /* XXX: FIX!! Next lines as an atomic operation? */ 340*d1b06863SMark Murray local_read_rate = read_rate; 341*d1b06863SMark Murray read_rate = RANDOM_ALG_READ_RATE_MINIMUM; 342*d1b06863SMark Murray LIST_FOREACH(rrs, &source_list, rrs_entries) { 343*d1b06863SMark Murray for (i = 0; i < random_alg_context.ra_poolcount*local_read_rate; i++) { 344*d1b06863SMark Murray n = rrs->rrs_source->rs_read(entropy, sizeof(entropy)); 345*d1b06863SMark Murray KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__)); 346*d1b06863SMark Murray random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source); 3475711939bSDavid E. O'Brien } 348*d1b06863SMark Murray } 349*d1b06863SMark Murray explicit_bzero(entropy, sizeof(entropy)); 350*d1b06863SMark Murray } 351*d1b06863SMark Murray 352*d1b06863SMark Murray static int 353*d1b06863SMark Murray random_source_handler(SYSCTL_HANDLER_ARGS) 354*d1b06863SMark Murray { 355*d1b06863SMark Murray struct random_sources *rrs; 356*d1b06863SMark Murray struct sbuf sbuf; 357*d1b06863SMark Murray int error, count; 358*d1b06863SMark Murray 359*d1b06863SMark Murray sbuf_new_for_sysctl(&sbuf, NULL, 64, req); 360*d1b06863SMark Murray count = 0; 361*d1b06863SMark Murray LIST_FOREACH(rrs, &source_list, rrs_entries) { 362*d1b06863SMark Murray sbuf_cat(&sbuf, (count++ ? ",'" : "'")); 363*d1b06863SMark Murray sbuf_cat(&sbuf, rrs->rrs_source->rs_ident); 364*d1b06863SMark Murray sbuf_cat(&sbuf, "'"); 365*d1b06863SMark Murray } 366*d1b06863SMark Murray error = sbuf_finish(&sbuf); 367*d1b06863SMark Murray sbuf_delete(&sbuf); 368*d1b06863SMark Murray return (error); 369*d1b06863SMark Murray } 370*d1b06863SMark Murray SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 371*d1b06863SMark Murray NULL, 0, random_source_handler, "A", 372*d1b06863SMark Murray "List of active fast entropy sources."); 373*d1b06863SMark Murray #endif /* !defined(RANDOM_DUMMY) */ 3745711939bSDavid E. O'Brien 375e1199601SMark Murray /* ARGSUSED */ 376a6278a2aSMark Murray static int 37710cb2424SMark Murray randomdev_modevent(module_t mod __unused, int type, void *data __unused) 3784db9ae91SMark Murray { 379e7806b4cSMark Murray int error = 0; 3804d87a031SMark Murray 3814db9ae91SMark Murray switch (type) { 3824db9ae91SMark Murray case MOD_LOAD: 383*d1b06863SMark Murray printf("random: entropy device external interface\n"); 38410cb2424SMark Murray random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, 38510cb2424SMark Murray RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0644, "random"); 38610cb2424SMark Murray make_dev_alias(random_dev, "urandom"); /* compatibility */ 387e7806b4cSMark Murray break; 3884db9ae91SMark Murray case MOD_UNLOAD: 389c9ec235cSMark Murray destroy_dev(random_dev); 390e7806b4cSMark Murray break; 3914db9ae91SMark Murray case MOD_SHUTDOWN: 392e7806b4cSMark Murray break; 3933e019deaSPoul-Henning Kamp default: 3943e019deaSPoul-Henning Kamp error = EOPNOTSUPP; 3953e019deaSPoul-Henning Kamp break; 3964db9ae91SMark Murray } 397e7806b4cSMark Murray return (error); 3984db9ae91SMark Murray } 3994db9ae91SMark Murray 400*d1b06863SMark Murray static moduledata_t randomdev_mod = { 401*d1b06863SMark Murray "random_device", 402*d1b06863SMark Murray randomdev_modevent, 403*d1b06863SMark Murray 0 404*d1b06863SMark Murray }; 40510cb2424SMark Murray 406*d1b06863SMark Murray DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 407*d1b06863SMark Murray MODULE_VERSION(random_device, 1); 408