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 = { 657ac40f5fSPoul-Henning Kamp .d_open = random_open, 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", 727ac40f5fSPoul-Henning Kamp .d_maj = CDEV_MAJOR, 734db9ae91SMark Murray }; 744db9ae91SMark Murray 7502c986abSMark Murray static void random_kthread(void *); 7602c986abSMark Murray static void random_harvest_internal(u_int64_t, void *, u_int, u_int, u_int, enum esource); 77e1199601SMark Murray static void random_write_internal(void *, int); 7802c986abSMark Murray 7902c986abSMark Murray /* Ring buffer holding harvested entropy */ 8002c986abSMark Murray static struct harvestring { 8102c986abSMark Murray volatile u_int head; 8202c986abSMark Murray volatile u_int tail; 8302c986abSMark Murray struct harvest data[HARVEST_RING_SIZE]; 8402c986abSMark Murray } harvestring; 8502c986abSMark Murray 8602c986abSMark Murray static struct random_systat { 8702c986abSMark Murray u_int seeded; /* 0 causes blocking 1 allows normal output */ 8802c986abSMark Murray u_int burst; /* number of events to do before sleeping */ 8902c986abSMark Murray struct selinfo rsel; /* For poll(2) */ 9002c986abSMark Murray } random_systat; 9102c986abSMark Murray 9202c986abSMark Murray /* <0 to end the kthread, 0 to let it run */ 9302c986abSMark Murray static int random_kthread_control = 0; 9402c986abSMark Murray 9502c986abSMark Murray static struct proc *random_kthread_proc; 9602c986abSMark Murray 974db9ae91SMark Murray /* For use with make_dev(9)/destroy_dev(9). */ 98c9ec235cSMark Murray static dev_t random_dev; 9902c986abSMark Murray static dev_t urandom_dev; 1004db9ae91SMark Murray 101e1199601SMark Murray /* ARGSUSED */ 10202c986abSMark Murray static int 10302c986abSMark Murray random_check_boolean(SYSCTL_HANDLER_ARGS) 10402c986abSMark Murray { 10502c986abSMark Murray if (oidp->oid_arg1 != NULL && *(u_int *)(oidp->oid_arg1) != 0) 10602c986abSMark Murray *(u_int *)(oidp->oid_arg1) = 1; 10702c986abSMark Murray return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); 10802c986abSMark Murray } 10902c986abSMark Murray 11002c986abSMark Murray RANDOM_CHECK_UINT(burst, 0, 20); 11102c986abSMark Murray 11202c986abSMark Murray SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 11302c986abSMark Murray 0, "Random Number Generator"); 11402c986abSMark Murray SYSCTL_NODE(_kern_random, OID_AUTO, sys, CTLFLAG_RW, 11502c986abSMark Murray 0, "Entropy Device Parameters"); 11602c986abSMark Murray SYSCTL_PROC(_kern_random_sys, OID_AUTO, seeded, 11702c986abSMark Murray CTLTYPE_INT|CTLFLAG_RW, &random_systat.seeded, 1, 11802c986abSMark Murray random_check_boolean, "I", "Seeded State"); 11902c986abSMark Murray SYSCTL_PROC(_kern_random_sys, OID_AUTO, burst, 12002c986abSMark Murray CTLTYPE_INT|CTLFLAG_RW, &random_systat.burst, 20, 12102c986abSMark Murray random_check_uint_burst, "I", "Harvest Burst Size"); 12202c986abSMark Murray SYSCTL_NODE(_kern_random_sys, OID_AUTO, harvest, CTLFLAG_RW, 12302c986abSMark Murray 0, "Entropy Sources"); 12402c986abSMark Murray SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, ethernet, 12502c986abSMark Murray CTLTYPE_INT|CTLFLAG_RW, &harvest.ethernet, 0, 12602c986abSMark Murray random_check_boolean, "I", "Harvest NIC entropy"); 12702c986abSMark Murray SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, point_to_point, 12802c986abSMark Murray CTLTYPE_INT|CTLFLAG_RW, &harvest.point_to_point, 0, 12902c986abSMark Murray random_check_boolean, "I", "Harvest serial net entropy"); 13002c986abSMark Murray SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, interrupt, 13102c986abSMark Murray CTLTYPE_INT|CTLFLAG_RW, &harvest.interrupt, 0, 13202c986abSMark Murray random_check_boolean, "I", "Harvest IRQ entropy"); 1334a7cdfd7SMark Murray SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, swi, 1344a7cdfd7SMark Murray CTLTYPE_INT|CTLFLAG_RW, &harvest.swi, 0, 1354a7cdfd7SMark Murray random_check_boolean, "I", "Harvest SWI entropy"); 1364db9ae91SMark Murray 137e1199601SMark Murray /* ARGSUSED */ 1384db9ae91SMark Murray static int 139e1199601SMark Murray random_open(dev_t dev __unused, int flags, int fmt __unused, struct thread *td) 1407aa4389aSMark Murray { 14119f15659SRobert Watson int error; 14219f15659SRobert Watson 14319f15659SRobert Watson if (flags & FWRITE) { 14444731cabSJohn Baldwin error = suser(td); 14519f15659SRobert Watson if (error) 14619f15659SRobert Watson return (error); 147a854ed98SJohn Baldwin error = securelevel_gt(td->td_ucred, 0); 14819f15659SRobert Watson if (error) 14919f15659SRobert Watson return (error); 15019f15659SRobert Watson } 1517aa4389aSMark Murray return 0; 1527aa4389aSMark Murray } 1537aa4389aSMark Murray 154e1199601SMark Murray /* ARGSUSED */ 1557aa4389aSMark Murray static int 156e1199601SMark Murray random_close(dev_t dev __unused, int flags, int fmt __unused, struct thread *td) 15750636159SMark Murray { 15819f15659SRobert Watson if (flags & FWRITE) { 15944731cabSJohn Baldwin if (!(suser(td) || 160a854ed98SJohn Baldwin securelevel_gt(td->td_ucred, 0))) 16150636159SMark Murray random_reseed(); 16219f15659SRobert Watson } 16350636159SMark Murray return 0; 16450636159SMark Murray } 16550636159SMark Murray 166e1199601SMark Murray /* ARGSUSED */ 16750636159SMark Murray static int 168e1199601SMark Murray random_read(dev_t dev __unused, struct uio *uio, int flag) 1694db9ae91SMark Murray { 170e1199601SMark Murray int c, ret; 1714db9ae91SMark Murray int error = 0; 172769afb04SMark Murray void *random_buf; 1734db9ae91SMark Murray 17402c986abSMark Murray while (!random_systat.seeded) { 17593d88e00SPeter Wemm if (flag & IO_NDELAY) 176a6278a2aSMark Murray error = EWOULDBLOCK; 17793d88e00SPeter Wemm else 17802c986abSMark Murray error = tsleep(&random_systat, PUSER|PCATCH, 17902c986abSMark Murray "block", 0); 18093d88e00SPeter Wemm if (error != 0) 18193d88e00SPeter Wemm return error; 182a6278a2aSMark Murray } 183e1199601SMark Murray c = uio->uio_resid < PAGE_SIZE ? uio->uio_resid : PAGE_SIZE; 184a163d034SWarner Losh random_buf = (void *)malloc((u_long)c, M_TEMP, M_WAITOK); 1854db9ae91SMark Murray while (uio->uio_resid > 0 && error == 0) { 186a6278a2aSMark Murray ret = read_random_real(random_buf, c); 187c9ec235cSMark Murray error = uiomove(random_buf, ret, uio); 1884db9ae91SMark Murray } 189c9ec235cSMark Murray free(random_buf, M_TEMP); 1904db9ae91SMark Murray return error; 1914db9ae91SMark Murray } 1924db9ae91SMark Murray 193e1199601SMark Murray /* ARGSUSED */ 1944db9ae91SMark Murray static int 195e1199601SMark Murray random_write(dev_t dev __unused, struct uio *uio, int flag __unused) 1964db9ae91SMark Murray { 197e1199601SMark Murray int c; 19802c986abSMark Murray int error; 199769afb04SMark Murray void *random_buf; 2004db9ae91SMark Murray 20102c986abSMark Murray error = 0; 202a163d034SWarner Losh random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 2034db9ae91SMark Murray while (uio->uio_resid > 0) { 204e1199601SMark Murray c = (int)(uio->uio_resid < PAGE_SIZE 205e1199601SMark Murray ? uio->uio_resid 206e1199601SMark Murray : PAGE_SIZE); 207c9ec235cSMark Murray error = uiomove(random_buf, c, uio); 2084db9ae91SMark Murray if (error) 2094db9ae91SMark Murray break; 21002c986abSMark Murray random_write_internal(random_buf, c); 2114db9ae91SMark Murray } 212c9ec235cSMark Murray free(random_buf, M_TEMP); 2134db9ae91SMark Murray return error; 2144db9ae91SMark Murray } 2154db9ae91SMark Murray 216e1199601SMark Murray /* ARGSUSED */ 2174db9ae91SMark Murray static int 218e1199601SMark Murray random_ioctl(dev_t dev __unused, u_long cmd, caddr_t addr __unused, 219e1199601SMark Murray int flags __unused, struct thread *td __unused) 2204d87a031SMark Murray { 22141bc9751SMark Murray switch (cmd) { 22241bc9751SMark Murray /* Really handled in upper layer */ 22341bc9751SMark Murray case FIOASYNC: 22441bc9751SMark Murray case FIONBIO: 22541bc9751SMark Murray return 0; 22641bc9751SMark Murray default: 2274d87a031SMark Murray return ENOTTY; 2284d87a031SMark Murray } 22941bc9751SMark Murray } 2304d87a031SMark Murray 231e1199601SMark Murray /* ARGSUSED */ 2324d87a031SMark Murray static int 233e1199601SMark Murray random_poll(dev_t dev __unused, int events, struct thread *td) 234a6278a2aSMark Murray { 235a6278a2aSMark Murray int revents; 236a6278a2aSMark Murray 237a6278a2aSMark Murray revents = 0; 238a6278a2aSMark Murray if (events & (POLLIN | POLLRDNORM)) { 23902c986abSMark Murray if (random_systat.seeded) 240a6278a2aSMark Murray revents = events & (POLLIN | POLLRDNORM); 241a6278a2aSMark Murray else 242ed01445dSJohn Baldwin selrecord(td, &random_systat.rsel); 243a6278a2aSMark Murray } 244a6278a2aSMark Murray return revents; 245a6278a2aSMark Murray } 246a6278a2aSMark Murray 247e1199601SMark Murray /* ARGSUSED */ 248a6278a2aSMark Murray static int 249e1199601SMark Murray random_modevent(module_t mod __unused, int type, void *data __unused) 2504db9ae91SMark Murray { 25102c986abSMark Murray int error; 2524d87a031SMark Murray 2534db9ae91SMark Murray switch(type) { 2544db9ae91SMark Murray case MOD_LOAD: 25502c986abSMark Murray random_init(); 256b79ad7e6SMark Murray 25702c986abSMark Murray /* This can be turned off by the very paranoid 25802c986abSMark Murray * a reseed will turn it back on. 25902c986abSMark Murray */ 26002c986abSMark Murray random_systat.seeded = 1; 26102c986abSMark Murray 26202c986abSMark Murray /* Number of envents to process off the harvest 26302c986abSMark Murray * queue before giving it a break and sleeping 26402c986abSMark Murray */ 26502c986abSMark Murray random_systat.burst = 20; 26602c986abSMark Murray 26702c986abSMark Murray /* Initialise the harvest ringbuffer */ 26802c986abSMark Murray harvestring.head = 0; 26902c986abSMark Murray harvestring.tail = 0; 270b79ad7e6SMark Murray 2714db9ae91SMark Murray if (bootverbose) 2724db9ae91SMark Murray printf("random: <entropy source>\n"); 273c9ec235cSMark Murray random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, UID_ROOT, 2741f67cd87SMark Murray GID_WHEEL, 0666, "random"); 27502c986abSMark Murray urandom_dev = make_dev_alias(random_dev, "urandom"); 27602c986abSMark Murray 27702c986abSMark Murray /* Start the hash/reseed thread */ 27802c986abSMark Murray error = kthread_create(random_kthread, NULL, 279316ec49aSScott Long &random_kthread_proc, RFHIGHPID, 0, "random"); 28002c986abSMark Murray if (error != 0) 28102c986abSMark Murray return error; 28202c986abSMark Murray 28302c986abSMark Murray /* Register the randomness harvesting routine */ 28402c986abSMark Murray random_init_harvester(random_harvest_internal, 28502c986abSMark Murray read_random_real); 28602c986abSMark Murray 2874db9ae91SMark Murray return 0; 2884db9ae91SMark Murray 2894db9ae91SMark Murray case MOD_UNLOAD: 29002c986abSMark Murray /* Deregister the randomness harvesting routine */ 29102c986abSMark Murray random_deinit_harvester(); 29202c986abSMark Murray 29302c986abSMark Murray /* Command the hash/reseed thread to end and 29402c986abSMark Murray * wait for it to finish 29502c986abSMark Murray */ 29602c986abSMark Murray random_kthread_control = -1; 29702c986abSMark Murray tsleep((void *)&random_kthread_control, PUSER, "term", 0); 29802c986abSMark Murray 299c9ec235cSMark Murray random_deinit(); 30002c986abSMark Murray 301c9ec235cSMark Murray destroy_dev(random_dev); 30202c986abSMark Murray destroy_dev(urandom_dev); 3034db9ae91SMark Murray return 0; 3044db9ae91SMark Murray 3054db9ae91SMark Murray case MOD_SHUTDOWN: 3064db9ae91SMark Murray return 0; 3074db9ae91SMark Murray 3084db9ae91SMark Murray default: 3094db9ae91SMark Murray return EOPNOTSUPP; 3104db9ae91SMark Murray } 3114db9ae91SMark Murray } 3124db9ae91SMark Murray 3134db9ae91SMark Murray DEV_MODULE(random, random_modevent, NULL); 31402c986abSMark Murray 315e1199601SMark Murray /* ARGSUSED */ 31602c986abSMark Murray static void 317e1199601SMark Murray random_kthread(void *arg __unused) 31802c986abSMark Murray { 31902c986abSMark Murray struct harvest *event; 320e1199601SMark Murray u_int newtail, burst; 32102c986abSMark Murray 32202c986abSMark Murray /* Drain the harvest queue (in 'burst' size chunks, 32302c986abSMark Murray * if 'burst' > 0. If 'burst' == 0, then completely 32402c986abSMark Murray * drain the queue. 32502c986abSMark Murray */ 32602c986abSMark Murray for (burst = 0; ; burst++) { 32702c986abSMark Murray 32802c986abSMark Murray if ((harvestring.tail == harvestring.head) || 32902c986abSMark Murray (random_systat.burst && burst == random_systat.burst)) { 33002c986abSMark Murray tsleep(&harvestring, PUSER, "sleep", hz/10); 33102c986abSMark Murray burst = 0; 33202c986abSMark Murray 33302c986abSMark Murray } 33402c986abSMark Murray else { 33502c986abSMark Murray 33602c986abSMark Murray /* Suck a harvested entropy event out of the queue and 33702c986abSMark Murray * hand it to the event processor 33802c986abSMark Murray */ 33902c986abSMark Murray 34002c986abSMark Murray newtail = (harvestring.tail + 1) & HARVEST_RING_MASK; 34102c986abSMark Murray event = &harvestring.data[harvestring.tail]; 34202c986abSMark Murray 34302c986abSMark Murray /* Bump the ring counter. This action is assumed 34402c986abSMark Murray * to be atomic. 34502c986abSMark Murray */ 34602c986abSMark Murray harvestring.tail = newtail; 34702c986abSMark Murray 34802c986abSMark Murray random_process_event(event); 34902c986abSMark Murray 35002c986abSMark Murray } 35102c986abSMark Murray 35202c986abSMark Murray /* Is the thread scheduled for a shutdown? */ 35302c986abSMark Murray if (random_kthread_control != 0) { 35402c986abSMark Murray #ifdef DEBUG 35502c986abSMark Murray printf("Random kthread setting terminate\n"); 35602c986abSMark Murray #endif 35702c986abSMark Murray random_set_wakeup_exit(&random_kthread_control); 35802c986abSMark Murray /* NOTREACHED */ 35902c986abSMark Murray break; 36002c986abSMark Murray } 36102c986abSMark Murray 36202c986abSMark Murray } 36302c986abSMark Murray 36402c986abSMark Murray } 36502c986abSMark Murray 36602c986abSMark Murray /* Entropy harvesting routine. This is supposed to be fast; do 36702c986abSMark Murray * not do anything slow in here! 36802c986abSMark Murray */ 36902c986abSMark Murray static void 37002c986abSMark Murray random_harvest_internal(u_int64_t somecounter, void *entropy, u_int count, 37102c986abSMark Murray u_int bits, u_int frac, enum esource origin) 37202c986abSMark Murray { 373e1199601SMark Murray struct harvest *pharvest; 374e1199601SMark Murray u_int newhead; 37502c986abSMark Murray 37602c986abSMark Murray newhead = (harvestring.head + 1) & HARVEST_RING_MASK; 37702c986abSMark Murray 37802c986abSMark Murray if (newhead != harvestring.tail) { 37902c986abSMark Murray 38002c986abSMark Murray /* Add the harvested data to the ring buffer */ 38102c986abSMark Murray 382e1199601SMark Murray pharvest = &harvestring.data[harvestring.head]; 38302c986abSMark Murray 38402c986abSMark Murray /* Stuff the harvested data into the ring */ 385e1199601SMark Murray pharvest->somecounter = somecounter; 38602c986abSMark Murray count = count > HARVESTSIZE ? HARVESTSIZE : count; 387e1199601SMark Murray memcpy(pharvest->entropy, entropy, count); 388e1199601SMark Murray pharvest->size = count; 389e1199601SMark Murray pharvest->bits = bits; 390e1199601SMark Murray pharvest->frac = frac; 391e1199601SMark Murray pharvest->source = 392e1199601SMark Murray origin < ENTROPYSOURCE ? origin : RANDOM_START; 39302c986abSMark Murray 39402c986abSMark Murray /* Bump the ring counter. This action is assumed 39502c986abSMark Murray * to be atomic. 39602c986abSMark Murray */ 39702c986abSMark Murray harvestring.head = newhead; 39802c986abSMark Murray 39902c986abSMark Murray } 40002c986abSMark Murray 40102c986abSMark Murray } 40202c986abSMark Murray 40302c986abSMark Murray static void 404e1199601SMark Murray random_write_internal(void *buf, int count) 40502c986abSMark Murray { 406e1199601SMark Murray int i; 40702c986abSMark Murray 40802c986abSMark Murray /* Break the input up into HARVESTSIZE chunks. 40902c986abSMark Murray * The writer has too much control here, so "estimate" the 41002c986abSMark Murray * the entropy as zero. 41102c986abSMark Murray */ 41202c986abSMark Murray for (i = 0; i < count; i += HARVESTSIZE) { 41302c986abSMark Murray random_harvest_internal(get_cyclecount(), (char *)buf + i, 41402c986abSMark Murray HARVESTSIZE, 0, 0, RANDOM_WRITE); 41502c986abSMark Murray } 41602c986abSMark Murray 41702c986abSMark Murray /* Maybe the loop iterated at least once */ 41802c986abSMark Murray if (i > count) 41902c986abSMark Murray i -= HARVESTSIZE; 42002c986abSMark Murray 42102c986abSMark Murray /* Get the last bytes even if the input length is not 42202c986abSMark Murray * a multiple of HARVESTSIZE. 42302c986abSMark Murray */ 42402c986abSMark Murray count %= HARVESTSIZE; 42502c986abSMark Murray if (count) { 42602c986abSMark Murray random_harvest_internal(get_cyclecount(), (char *)buf + i, 427e1199601SMark Murray (u_int)count, 0, 0, RANDOM_WRITE); 42802c986abSMark Murray } 42902c986abSMark Murray } 43002c986abSMark Murray 43102c986abSMark Murray void 43202c986abSMark Murray random_unblock(void) 43302c986abSMark Murray { 43402c986abSMark Murray if (!random_systat.seeded) { 43502c986abSMark Murray random_systat.seeded = 1; 43602c986abSMark Murray selwakeup(&random_systat.rsel); 43702c986abSMark Murray wakeup(&random_systat); 43802c986abSMark Murray } 43902c986abSMark Murray } 440