14db9ae91SMark Murray /*- 2c9ec235cSMark Murray * Copyright (c) 2000 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 * $FreeBSD$ 274db9ae91SMark Murray */ 284db9ae91SMark Murray 294db9ae91SMark Murray #include <sys/param.h> 304db9ae91SMark Murray #include <sys/systm.h> 31fb919e4dSMark Murray #include <sys/bus.h> 324db9ae91SMark Murray #include <sys/conf.h> 334db9ae91SMark Murray #include <sys/fcntl.h> 34fb919e4dSMark Murray #include <sys/filio.h> 354db9ae91SMark Murray #include <sys/kernel.h> 3602c986abSMark Murray #include <sys/kthread.h> 37fb919e4dSMark Murray #include <sys/lock.h> 384db9ae91SMark Murray #include <sys/malloc.h> 39fb919e4dSMark Murray #include <sys/mutex.h> 40a6278a2aSMark Murray #include <sys/poll.h> 41b40ce416SJulian Elischer #include <sys/proc.h> 424db9ae91SMark Murray #include <sys/random.h> 43fb919e4dSMark Murray #include <sys/selinfo.h> 44b79ad7e6SMark Murray #include <sys/sysctl.h> 45fb919e4dSMark Murray #include <sys/uio.h> 4602c986abSMark Murray #include <sys/unistd.h> 47fb919e4dSMark Murray #include <sys/vnode.h> 484db9ae91SMark Murray 4902c986abSMark Murray #include <machine/bus.h> 5002c986abSMark Murray #include <machine/cpu.h> 5102c986abSMark Murray 5202c986abSMark Murray #include <dev/random/randomdev.h> 534db9ae91SMark Murray 547aa4389aSMark Murray static d_open_t random_open; 5550636159SMark Murray static d_close_t random_close; 56c9ec235cSMark Murray static d_read_t random_read; 57c9ec235cSMark Murray static d_write_t random_write; 584d87a031SMark Murray static d_ioctl_t random_ioctl; 59a6278a2aSMark Murray static d_poll_t random_poll; 604db9ae91SMark Murray 614db9ae91SMark Murray #define CDEV_MAJOR 2 624db9ae91SMark Murray #define RANDOM_MINOR 3 634db9ae91SMark Murray 644db9ae91SMark Murray static struct cdevsw random_cdevsw = { 657aa4389aSMark Murray /* open */ random_open, 6650636159SMark Murray /* close */ random_close, 67c9ec235cSMark Murray /* read */ random_read, 68c9ec235cSMark Murray /* write */ random_write, 694d87a031SMark Murray /* ioctl */ random_ioctl, 70a6278a2aSMark Murray /* poll */ random_poll, 714db9ae91SMark Murray /* mmap */ nommap, 724db9ae91SMark Murray /* strategy */ nostrategy, 734db9ae91SMark Murray /* name */ "random", 744db9ae91SMark Murray /* maj */ CDEV_MAJOR, 754db9ae91SMark Murray /* dump */ nodump, 764db9ae91SMark Murray /* psize */ nopsize, 774db9ae91SMark Murray /* flags */ 0, 78e1199601SMark Murray /* kqfilter */ NULL 794db9ae91SMark Murray }; 804db9ae91SMark Murray 8102c986abSMark Murray static void random_kthread(void *); 8202c986abSMark Murray static void random_harvest_internal(u_int64_t, void *, u_int, u_int, u_int, enum esource); 83e1199601SMark Murray static void random_write_internal(void *, int); 8402c986abSMark Murray 8502c986abSMark Murray /* Ring buffer holding harvested entropy */ 8602c986abSMark Murray static struct harvestring { 8702c986abSMark Murray volatile u_int head; 8802c986abSMark Murray volatile u_int tail; 8902c986abSMark Murray struct harvest data[HARVEST_RING_SIZE]; 9002c986abSMark Murray } harvestring; 9102c986abSMark Murray 9202c986abSMark Murray static struct random_systat { 9302c986abSMark Murray u_int seeded; /* 0 causes blocking 1 allows normal output */ 9402c986abSMark Murray u_int burst; /* number of events to do before sleeping */ 9502c986abSMark Murray struct selinfo rsel; /* For poll(2) */ 9602c986abSMark Murray } random_systat; 9702c986abSMark Murray 9802c986abSMark Murray /* <0 to end the kthread, 0 to let it run */ 9902c986abSMark Murray static int random_kthread_control = 0; 10002c986abSMark Murray 10102c986abSMark Murray static struct proc *random_kthread_proc; 10202c986abSMark Murray 1034db9ae91SMark Murray /* For use with make_dev(9)/destroy_dev(9). */ 104c9ec235cSMark Murray static dev_t random_dev; 10502c986abSMark Murray static dev_t urandom_dev; 1064db9ae91SMark Murray 107e1199601SMark Murray /* ARGSUSED */ 10802c986abSMark Murray static int 10902c986abSMark Murray random_check_boolean(SYSCTL_HANDLER_ARGS) 11002c986abSMark Murray { 11102c986abSMark Murray if (oidp->oid_arg1 != NULL && *(u_int *)(oidp->oid_arg1) != 0) 11202c986abSMark Murray *(u_int *)(oidp->oid_arg1) = 1; 11302c986abSMark Murray return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); 11402c986abSMark Murray } 11502c986abSMark Murray 11602c986abSMark Murray RANDOM_CHECK_UINT(burst, 0, 20); 11702c986abSMark Murray 11802c986abSMark Murray SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 11902c986abSMark Murray 0, "Random Number Generator"); 12002c986abSMark Murray SYSCTL_NODE(_kern_random, OID_AUTO, sys, CTLFLAG_RW, 12102c986abSMark Murray 0, "Entropy Device Parameters"); 12202c986abSMark Murray SYSCTL_PROC(_kern_random_sys, OID_AUTO, seeded, 12302c986abSMark Murray CTLTYPE_INT|CTLFLAG_RW, &random_systat.seeded, 1, 12402c986abSMark Murray random_check_boolean, "I", "Seeded State"); 12502c986abSMark Murray SYSCTL_PROC(_kern_random_sys, OID_AUTO, burst, 12602c986abSMark Murray CTLTYPE_INT|CTLFLAG_RW, &random_systat.burst, 20, 12702c986abSMark Murray random_check_uint_burst, "I", "Harvest Burst Size"); 12802c986abSMark Murray SYSCTL_NODE(_kern_random_sys, OID_AUTO, harvest, CTLFLAG_RW, 12902c986abSMark Murray 0, "Entropy Sources"); 13002c986abSMark Murray SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, ethernet, 13102c986abSMark Murray CTLTYPE_INT|CTLFLAG_RW, &harvest.ethernet, 0, 13202c986abSMark Murray random_check_boolean, "I", "Harvest NIC entropy"); 13302c986abSMark Murray SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, point_to_point, 13402c986abSMark Murray CTLTYPE_INT|CTLFLAG_RW, &harvest.point_to_point, 0, 13502c986abSMark Murray random_check_boolean, "I", "Harvest serial net entropy"); 13602c986abSMark Murray SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, interrupt, 13702c986abSMark Murray CTLTYPE_INT|CTLFLAG_RW, &harvest.interrupt, 0, 13802c986abSMark Murray random_check_boolean, "I", "Harvest IRQ entropy"); 1394db9ae91SMark Murray 140e1199601SMark Murray /* ARGSUSED */ 1414db9ae91SMark Murray static int 142e1199601SMark Murray random_open(dev_t dev __unused, int flags, int fmt __unused, struct thread *td) 1437aa4389aSMark Murray { 14419f15659SRobert Watson int error; 14519f15659SRobert Watson 14619f15659SRobert Watson if (flags & FWRITE) { 14719f15659SRobert Watson error = suser(td->td_proc); 14819f15659SRobert Watson if (error) 14919f15659SRobert Watson return (error); 150a854ed98SJohn Baldwin error = securelevel_gt(td->td_ucred, 0); 15119f15659SRobert Watson if (error) 15219f15659SRobert Watson return (error); 15319f15659SRobert Watson } 1547aa4389aSMark Murray return 0; 1557aa4389aSMark Murray } 1567aa4389aSMark Murray 157e1199601SMark Murray /* ARGSUSED */ 1587aa4389aSMark Murray static int 159e1199601SMark Murray random_close(dev_t dev __unused, int flags, int fmt __unused, struct thread *td) 16050636159SMark Murray { 16119f15659SRobert Watson if (flags & FWRITE) { 16219f15659SRobert Watson if (!(suser(td->td_proc) || 163a854ed98SJohn Baldwin securelevel_gt(td->td_ucred, 0))) 16450636159SMark Murray random_reseed(); 16519f15659SRobert Watson } 16650636159SMark Murray return 0; 16750636159SMark Murray } 16850636159SMark Murray 169e1199601SMark Murray /* ARGSUSED */ 17050636159SMark Murray static int 171e1199601SMark Murray random_read(dev_t dev __unused, struct uio *uio, int flag) 1724db9ae91SMark Murray { 173e1199601SMark Murray int c, ret; 1744db9ae91SMark Murray int error = 0; 175769afb04SMark Murray void *random_buf; 1764db9ae91SMark Murray 17702c986abSMark Murray while (!random_systat.seeded) { 17893d88e00SPeter Wemm if (flag & IO_NDELAY) 179a6278a2aSMark Murray error = EWOULDBLOCK; 18093d88e00SPeter Wemm else 18102c986abSMark Murray error = tsleep(&random_systat, PUSER|PCATCH, 18202c986abSMark Murray "block", 0); 18393d88e00SPeter Wemm if (error != 0) 18493d88e00SPeter Wemm return error; 185a6278a2aSMark Murray } 186e1199601SMark Murray c = uio->uio_resid < PAGE_SIZE ? uio->uio_resid : PAGE_SIZE; 187e1199601SMark Murray random_buf = (void *)malloc((u_long)c, M_TEMP, M_WAITOK); 1884db9ae91SMark Murray while (uio->uio_resid > 0 && error == 0) { 189a6278a2aSMark Murray ret = read_random_real(random_buf, c); 190c9ec235cSMark Murray error = uiomove(random_buf, ret, uio); 1914db9ae91SMark Murray } 192c9ec235cSMark Murray free(random_buf, M_TEMP); 1934db9ae91SMark Murray return error; 1944db9ae91SMark Murray } 1954db9ae91SMark Murray 196e1199601SMark Murray /* ARGSUSED */ 1974db9ae91SMark Murray static int 198e1199601SMark Murray random_write(dev_t dev __unused, struct uio *uio, int flag __unused) 1994db9ae91SMark Murray { 200e1199601SMark Murray int c; 20102c986abSMark Murray int error; 202769afb04SMark Murray void *random_buf; 2034db9ae91SMark Murray 20402c986abSMark Murray error = 0; 205c9ec235cSMark Murray random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 2064db9ae91SMark Murray while (uio->uio_resid > 0) { 207e1199601SMark Murray c = (int)(uio->uio_resid < PAGE_SIZE 208e1199601SMark Murray ? uio->uio_resid 209e1199601SMark Murray : PAGE_SIZE); 210c9ec235cSMark Murray error = uiomove(random_buf, c, uio); 2114db9ae91SMark Murray if (error) 2124db9ae91SMark Murray break; 21302c986abSMark Murray random_write_internal(random_buf, c); 2144db9ae91SMark Murray } 215c9ec235cSMark Murray free(random_buf, M_TEMP); 2164db9ae91SMark Murray return error; 2174db9ae91SMark Murray } 2184db9ae91SMark Murray 219e1199601SMark Murray /* ARGSUSED */ 2204db9ae91SMark Murray static int 221e1199601SMark Murray random_ioctl(dev_t dev __unused, u_long cmd, caddr_t addr __unused, 222e1199601SMark Murray int flags __unused, struct thread *td __unused) 2234d87a031SMark Murray { 22441bc9751SMark Murray switch (cmd) { 22541bc9751SMark Murray /* Really handled in upper layer */ 22641bc9751SMark Murray case FIOASYNC: 22741bc9751SMark Murray case FIONBIO: 22841bc9751SMark Murray return 0; 22941bc9751SMark Murray default: 2304d87a031SMark Murray return ENOTTY; 2314d87a031SMark Murray } 23241bc9751SMark Murray } 2334d87a031SMark Murray 234e1199601SMark Murray /* ARGSUSED */ 2354d87a031SMark Murray static int 236e1199601SMark Murray random_poll(dev_t dev __unused, int events, struct thread *td) 237a6278a2aSMark Murray { 238a6278a2aSMark Murray int revents; 239a6278a2aSMark Murray 240a6278a2aSMark Murray revents = 0; 241a6278a2aSMark Murray if (events & (POLLIN | POLLRDNORM)) { 24202c986abSMark Murray if (random_systat.seeded) 243a6278a2aSMark Murray revents = events & (POLLIN | POLLRDNORM); 244a6278a2aSMark Murray else 245ed01445dSJohn Baldwin selrecord(td, &random_systat.rsel); 246a6278a2aSMark Murray } 247a6278a2aSMark Murray return revents; 248a6278a2aSMark Murray } 249a6278a2aSMark Murray 250e1199601SMark Murray /* ARGSUSED */ 251a6278a2aSMark Murray static int 252e1199601SMark Murray random_modevent(module_t mod __unused, int type, void *data __unused) 2534db9ae91SMark Murray { 25402c986abSMark Murray int error; 2554d87a031SMark Murray 2564db9ae91SMark Murray switch(type) { 2574db9ae91SMark Murray case MOD_LOAD: 25802c986abSMark Murray random_init(); 259b79ad7e6SMark Murray 26002c986abSMark Murray /* This can be turned off by the very paranoid 26102c986abSMark Murray * a reseed will turn it back on. 26202c986abSMark Murray */ 26302c986abSMark Murray random_systat.seeded = 1; 26402c986abSMark Murray 26502c986abSMark Murray /* Number of envents to process off the harvest 26602c986abSMark Murray * queue before giving it a break and sleeping 26702c986abSMark Murray */ 26802c986abSMark Murray random_systat.burst = 20; 26902c986abSMark Murray 27002c986abSMark Murray /* Initialise the harvest ringbuffer */ 27102c986abSMark Murray harvestring.head = 0; 27202c986abSMark Murray harvestring.tail = 0; 273b79ad7e6SMark Murray 2744db9ae91SMark Murray if (bootverbose) 2754db9ae91SMark Murray printf("random: <entropy source>\n"); 276c9ec235cSMark Murray random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, UID_ROOT, 2771f67cd87SMark Murray GID_WHEEL, 0666, "random"); 27802c986abSMark Murray urandom_dev = make_dev_alias(random_dev, "urandom"); 27902c986abSMark Murray 28002c986abSMark Murray /* Start the hash/reseed thread */ 28102c986abSMark Murray error = kthread_create(random_kthread, NULL, 28202c986abSMark Murray &random_kthread_proc, RFHIGHPID, "random"); 28302c986abSMark Murray if (error != 0) 28402c986abSMark Murray return error; 28502c986abSMark Murray 28602c986abSMark Murray /* Register the randomness harvesting routine */ 28702c986abSMark Murray random_init_harvester(random_harvest_internal, 28802c986abSMark Murray read_random_real); 28902c986abSMark Murray 2904db9ae91SMark Murray return 0; 2914db9ae91SMark Murray 2924db9ae91SMark Murray case MOD_UNLOAD: 29302c986abSMark Murray /* Deregister the randomness harvesting routine */ 29402c986abSMark Murray random_deinit_harvester(); 29502c986abSMark Murray 29602c986abSMark Murray /* Command the hash/reseed thread to end and 29702c986abSMark Murray * wait for it to finish 29802c986abSMark Murray */ 29902c986abSMark Murray random_kthread_control = -1; 30002c986abSMark Murray tsleep((void *)&random_kthread_control, PUSER, "term", 0); 30102c986abSMark Murray 302c9ec235cSMark Murray random_deinit(); 30302c986abSMark Murray 304c9ec235cSMark Murray destroy_dev(random_dev); 30502c986abSMark Murray destroy_dev(urandom_dev); 3064db9ae91SMark Murray return 0; 3074db9ae91SMark Murray 3084db9ae91SMark Murray case MOD_SHUTDOWN: 3094db9ae91SMark Murray return 0; 3104db9ae91SMark Murray 3114db9ae91SMark Murray default: 3124db9ae91SMark Murray return EOPNOTSUPP; 3134db9ae91SMark Murray } 3144db9ae91SMark Murray } 3154db9ae91SMark Murray 3164db9ae91SMark Murray DEV_MODULE(random, random_modevent, NULL); 31702c986abSMark Murray 318e1199601SMark Murray /* ARGSUSED */ 31902c986abSMark Murray static void 320e1199601SMark Murray random_kthread(void *arg __unused) 32102c986abSMark Murray { 32202c986abSMark Murray struct harvest *event; 323e1199601SMark Murray u_int newtail, burst; 32402c986abSMark Murray 32502c986abSMark Murray /* Drain the harvest queue (in 'burst' size chunks, 32602c986abSMark Murray * if 'burst' > 0. If 'burst' == 0, then completely 32702c986abSMark Murray * drain the queue. 32802c986abSMark Murray */ 32902c986abSMark Murray for (burst = 0; ; burst++) { 33002c986abSMark Murray 33102c986abSMark Murray if ((harvestring.tail == harvestring.head) || 33202c986abSMark Murray (random_systat.burst && burst == random_systat.burst)) { 33302c986abSMark Murray tsleep(&harvestring, PUSER, "sleep", hz/10); 33402c986abSMark Murray burst = 0; 33502c986abSMark Murray 33602c986abSMark Murray } 33702c986abSMark Murray else { 33802c986abSMark Murray 33902c986abSMark Murray /* Suck a harvested entropy event out of the queue and 34002c986abSMark Murray * hand it to the event processor 34102c986abSMark Murray */ 34202c986abSMark Murray 34302c986abSMark Murray newtail = (harvestring.tail + 1) & HARVEST_RING_MASK; 34402c986abSMark Murray event = &harvestring.data[harvestring.tail]; 34502c986abSMark Murray 34602c986abSMark Murray /* Bump the ring counter. This action is assumed 34702c986abSMark Murray * to be atomic. 34802c986abSMark Murray */ 34902c986abSMark Murray harvestring.tail = newtail; 35002c986abSMark Murray 35102c986abSMark Murray random_process_event(event); 35202c986abSMark Murray 35302c986abSMark Murray } 35402c986abSMark Murray 35502c986abSMark Murray /* Is the thread scheduled for a shutdown? */ 35602c986abSMark Murray if (random_kthread_control != 0) { 35702c986abSMark Murray #ifdef DEBUG 35802c986abSMark Murray mtx_lock(&Giant); 35902c986abSMark Murray printf("Random kthread setting terminate\n"); 36002c986abSMark Murray mtx_unlock(&Giant); 36102c986abSMark Murray #endif 36202c986abSMark Murray random_set_wakeup_exit(&random_kthread_control); 36302c986abSMark Murray /* NOTREACHED */ 36402c986abSMark Murray break; 36502c986abSMark Murray } 36602c986abSMark Murray 36702c986abSMark Murray } 36802c986abSMark Murray 36902c986abSMark Murray } 37002c986abSMark Murray 37102c986abSMark Murray /* Entropy harvesting routine. This is supposed to be fast; do 37202c986abSMark Murray * not do anything slow in here! 37302c986abSMark Murray */ 37402c986abSMark Murray static void 37502c986abSMark Murray random_harvest_internal(u_int64_t somecounter, void *entropy, u_int count, 37602c986abSMark Murray u_int bits, u_int frac, enum esource origin) 37702c986abSMark Murray { 378e1199601SMark Murray struct harvest *pharvest; 379e1199601SMark Murray u_int newhead; 38002c986abSMark Murray 38102c986abSMark Murray newhead = (harvestring.head + 1) & HARVEST_RING_MASK; 38202c986abSMark Murray 38302c986abSMark Murray if (newhead != harvestring.tail) { 38402c986abSMark Murray 38502c986abSMark Murray /* Add the harvested data to the ring buffer */ 38602c986abSMark Murray 387e1199601SMark Murray pharvest = &harvestring.data[harvestring.head]; 38802c986abSMark Murray 38902c986abSMark Murray /* Stuff the harvested data into the ring */ 390e1199601SMark Murray pharvest->somecounter = somecounter; 39102c986abSMark Murray count = count > HARVESTSIZE ? HARVESTSIZE : count; 392e1199601SMark Murray memcpy(pharvest->entropy, entropy, count); 393e1199601SMark Murray pharvest->size = count; 394e1199601SMark Murray pharvest->bits = bits; 395e1199601SMark Murray pharvest->frac = frac; 396e1199601SMark Murray pharvest->source = 397e1199601SMark Murray origin < ENTROPYSOURCE ? origin : RANDOM_START; 39802c986abSMark Murray 39902c986abSMark Murray /* Bump the ring counter. This action is assumed 40002c986abSMark Murray * to be atomic. 40102c986abSMark Murray */ 40202c986abSMark Murray harvestring.head = newhead; 40302c986abSMark Murray 40402c986abSMark Murray } 40502c986abSMark Murray 40602c986abSMark Murray } 40702c986abSMark Murray 40802c986abSMark Murray static void 409e1199601SMark Murray random_write_internal(void *buf, int count) 41002c986abSMark Murray { 411e1199601SMark Murray int i; 41202c986abSMark Murray 41302c986abSMark Murray /* Break the input up into HARVESTSIZE chunks. 41402c986abSMark Murray * The writer has too much control here, so "estimate" the 41502c986abSMark Murray * the entropy as zero. 41602c986abSMark Murray */ 41702c986abSMark Murray for (i = 0; i < count; i += HARVESTSIZE) { 41802c986abSMark Murray random_harvest_internal(get_cyclecount(), (char *)buf + i, 41902c986abSMark Murray HARVESTSIZE, 0, 0, RANDOM_WRITE); 42002c986abSMark Murray } 42102c986abSMark Murray 42202c986abSMark Murray /* Maybe the loop iterated at least once */ 42302c986abSMark Murray if (i > count) 42402c986abSMark Murray i -= HARVESTSIZE; 42502c986abSMark Murray 42602c986abSMark Murray /* Get the last bytes even if the input length is not 42702c986abSMark Murray * a multiple of HARVESTSIZE. 42802c986abSMark Murray */ 42902c986abSMark Murray count %= HARVESTSIZE; 43002c986abSMark Murray if (count) { 43102c986abSMark Murray random_harvest_internal(get_cyclecount(), (char *)buf + i, 432e1199601SMark Murray (u_int)count, 0, 0, RANDOM_WRITE); 43302c986abSMark Murray } 43402c986abSMark Murray } 43502c986abSMark Murray 43602c986abSMark Murray void 43702c986abSMark Murray random_unblock(void) 43802c986abSMark Murray { 43902c986abSMark Murray if (!random_systat.seeded) { 44002c986abSMark Murray random_systat.seeded = 1; 44102c986abSMark Murray selwakeup(&random_systat.rsel); 44202c986abSMark Murray wakeup(&random_systat); 44302c986abSMark Murray } 44402c986abSMark Murray } 445