yarrow.c revision 72200
162053Smarkm/*- 262765Smarkm * Copyright (c) 2000 Mark R V Murray 362053Smarkm * All rights reserved. 462053Smarkm * 562053Smarkm * Redistribution and use in source and binary forms, with or without 662053Smarkm * modification, are permitted provided that the following conditions 762053Smarkm * are met: 862053Smarkm * 1. Redistributions of source code must retain the above copyright 962053Smarkm * notice, this list of conditions and the following disclaimer 1062053Smarkm * in this position and unchanged. 1162053Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1262053Smarkm * notice, this list of conditions and the following disclaimer in the 1362053Smarkm * documentation and/or other materials provided with the distribution. 1462053Smarkm * 1562053Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1662053Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1762053Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1862053Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1962053Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2062053Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2162053Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2262053Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2362053Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2462053Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2562053Smarkm * 2662053Smarkm * $FreeBSD: head/sys/dev/random/yarrow.c 72200 2001-02-09 06:11:45Z bmilekic $ 2762053Smarkm */ 2862053Smarkm 2962053Smarkm/* NOTE NOTE NOTE - This is not finished! It will supply numbers, but 3063771Smarkm * it is not yet cryptographically secure!! 3163771Smarkm */ 3262053Smarkm 3362053Smarkm#include <sys/param.h> 3462053Smarkm#include <sys/systm.h> 3565686Smarkm#include <sys/kernel.h> 3665686Smarkm#include <sys/kthread.h> 3762053Smarkm#include <sys/libkern.h> 3867365Sjhb#include <sys/mutex.h> 3970834Swollman#include <sys/selinfo.h> 4062053Smarkm#include <sys/random.h> 4162053Smarkm#include <sys/types.h> 4265712Sjhb#include <sys/unistd.h> 4369168Smarkm 4469526Smarkm#include <machine/atomic.h> 4569168Smarkm#include <machine/cpu.h> 4669168Smarkm 4762053Smarkm#include <crypto/blowfish/blowfish.h> 4862053Smarkm 4967112Smarkm#include <dev/random/hash.h> 5067112Smarkm#include <dev/random/yarrow.h> 5162053Smarkm 5262765Smarkm/* #define DEBUG */ 5365686Smarkm/* #define DEBUG1 */ /* Very noisy - prints plenty harvesting stats */ 5462053Smarkm 5562765Smarkmstatic void generator_gate(void); 5662765Smarkmstatic void reseed(int); 5769168Smarkmstatic void random_harvest_internal(u_int64_t, void *, u_int, u_int, u_int, enum esource); 5862053Smarkm 5965686Smarkmstatic void random_kthread(void *); 6065686Smarkm 6162765Smarkm/* Structure holding the entropy state */ 6262765Smarkmstruct random_state random_state; 6362765Smarkm 6465686Smarkm/* These are used to queue harvested packets of entropy. The entropy 6567112Smarkm * buffer size is pretty arbitrary. 6663771Smarkm */ 6765686Smarkmstruct harvest { 6869168Smarkm u_int64_t somecounter; /* fast counter for clock jitter */ 6967112Smarkm u_char entropy[HARVESTSIZE]; /* the harvested entropy */ 7065686Smarkm u_int size, bits, frac; /* stats about the entropy */ 7165686Smarkm enum esource source; /* stats about the entropy */ 7265686Smarkm u_int pool; /* which pool this goes into */ 7365686Smarkm}; 7462765Smarkm 7569526Smarkm/* Ring buffer holding harvested entropy */ 7669526Smarkmstatic struct harvestring { 7769526Smarkm struct mtx lockout_mtx; 7869526Smarkm int head; 7969526Smarkm int tail; 8069526Smarkm struct harvest data[HARVEST_RING_SIZE]; 8169526Smarkm} harvestring; 8269526Smarkm 8365686Smarkm/* The reseed thread mutex */ 8465856Sjhbstatic struct mtx random_reseed_mtx; 8562765Smarkm 8665686Smarkm/* <0 to end the kthread, 0 to let it run */ 8765686Smarkmstatic int random_kthread_control = 0; 8865686Smarkm 8965686Smarkmstatic struct proc *random_kthread_proc; 9065686Smarkm 9162765Smarkmstatic void 9267112Smarkmrandom_kthread(void *arg /* NOTUSED */) 9362765Smarkm{ 9469526Smarkm int pl, src, overthreshhold[2], head, newtail; 9565686Smarkm struct harvest *event; 9665686Smarkm struct source *source; 9765686Smarkm 9862765Smarkm#ifdef DEBUG 9972200Sbmilekic mtx_lock(&Giant); 10069526Smarkm printf("OWNERSHIP Giant == %d sched_lock == %d\n", 10169526Smarkm mtx_owned(&Giant), mtx_owned(&sched_lock)); 10272200Sbmilekic mtx_unlock(&Giant); 10362765Smarkm#endif 10465686Smarkm 10565686Smarkm for (pl = 0; pl < 2; pl++) 10665686Smarkm yarrow_hash_init(&random_state.pool[pl].hash, NULL, 0); 10765686Smarkm 10865686Smarkm for (;;) { 10965686Smarkm 11069526Smarkm head = atomic_load_acq_int(&harvestring.head); 11169526Smarkm newtail = (harvestring.tail + 1) % HARVEST_RING_SIZE; 11269526Smarkm if (harvestring.tail == head) 11369526Smarkm tsleep(&harvestring.head, PUSER, "rndslp", hz/10); 11465686Smarkm 11569526Smarkm else { 11669526Smarkm#ifdef DEBUG1 11772200Sbmilekic mtx_lock(&Giant); 11869526Smarkm printf("HARVEST src=%d bits=%d/%d pool=%d count=%lld\n", 11969526Smarkm event->source, event->bits, event->frac, 12069526Smarkm event->pool, event->somecounter); 12172200Sbmilekic mtx_unlock(&Giant); 12269526Smarkm#endif 12365686Smarkm 12465686Smarkm /* Suck the harvested entropy out of the queue and hash 12569526Smarkm * it into the appropriate pool. 12665686Smarkm */ 12765686Smarkm 12869526Smarkm event = &harvestring.data[harvestring.tail]; 12969526Smarkm harvestring.tail = newtail; 13065686Smarkm 13169526Smarkm source = &random_state.pool[event->pool].source[event->source]; 13269526Smarkm yarrow_hash_iterate(&random_state.pool[event->pool].hash, 13369526Smarkm event->entropy, sizeof(event->entropy)); 13469526Smarkm yarrow_hash_iterate(&random_state.pool[event->pool].hash, 13569526Smarkm &event->somecounter, sizeof(event->somecounter)); 13669526Smarkm source->frac += event->frac; 13769526Smarkm source->bits += event->bits + source->frac/1024; 13869526Smarkm source->frac %= 1024; 13965686Smarkm 14065686Smarkm /* Count the over-threshold sources in each pool */ 14165686Smarkm for (pl = 0; pl < 2; pl++) { 14265686Smarkm overthreshhold[pl] = 0; 14365686Smarkm for (src = 0; src < ENTROPYSOURCE; src++) { 14465686Smarkm if (random_state.pool[pl].source[src].bits 14565686Smarkm > random_state.pool[pl].thresh) 14665686Smarkm overthreshhold[pl]++; 14765686Smarkm } 14865686Smarkm } 14965686Smarkm 15065686Smarkm /* if any fast source over threshhold, reseed */ 15165686Smarkm if (overthreshhold[FAST]) 15265686Smarkm reseed(FAST); 15369526Smarkm 15465686Smarkm /* if enough slow sources are over threshhold, reseed */ 15565686Smarkm if (overthreshhold[SLOW] >= random_state.slowoverthresh) 15665686Smarkm reseed(SLOW); 15765686Smarkm 15865686Smarkm } 15965686Smarkm 16065686Smarkm /* Is the thread scheduled for a shutdown? */ 16167112Smarkm if (random_kthread_control != 0) { 16265686Smarkm#ifdef DEBUG 16372200Sbmilekic mtx_lock(&Giant); 16465686Smarkm printf("Random kthread setting terminate\n"); 16572200Sbmilekic mtx_unlock(&Giant); 16665686Smarkm#endif 16767112Smarkm random_set_wakeup_exit(&random_kthread_control); 16867112Smarkm /* NOTREACHED */ 16965686Smarkm break; 17065686Smarkm } 17165686Smarkm 17265686Smarkm } 17365686Smarkm 17462765Smarkm} 17562765Smarkm 17665686Smarkmint 17762765Smarkmrandom_init(void) 17862053Smarkm{ 17965686Smarkm int error; 18065686Smarkm 18162765Smarkm#ifdef DEBUG 18272200Sbmilekic mtx_lock(&Giant); 18365686Smarkm printf("Random initialise\n"); 18472200Sbmilekic mtx_unlock(&Giant); 18562765Smarkm#endif 18665686Smarkm 18771037Smarkm /* This can be turned off by the very paranoid 18871037Smarkm * a reseed will turn it back on. 18971037Smarkm */ 19071037Smarkm random_state.seeded = 1; 19171037Smarkm 19262765Smarkm random_state.gengateinterval = 10; 19362765Smarkm random_state.bins = 10; 19462765Smarkm random_state.pool[0].thresh = 100; 19562765Smarkm random_state.pool[1].thresh = 160; 19662765Smarkm random_state.slowoverthresh = 2; 19762765Smarkm random_state.which = FAST; 19865686Smarkm 19965686Smarkm /* Initialise the mutexes */ 20065686Smarkm mtx_init(&random_reseed_mtx, "random reseed", MTX_DEF); 20169526Smarkm mtx_init(&harvestring.lockout_mtx, "random harvest", MTX_DEF); 20265686Smarkm 20369526Smarkm harvestring.head = 0; 20469526Smarkm harvestring.tail = 0; 20569526Smarkm 20665686Smarkm /* Start the hash/reseed thread */ 20767112Smarkm error = kthread_create(random_kthread, NULL, 20865712Sjhb &random_kthread_proc, RFHIGHPID, "random"); 20965686Smarkm if (error != 0) 21065686Smarkm return error; 21165686Smarkm 21265686Smarkm /* Register the randomness harvesting routine */ 21367112Smarkm random_init_harvester(random_harvest_internal, read_random_real); 21465686Smarkm 21565686Smarkm#ifdef DEBUG 21672200Sbmilekic mtx_lock(&Giant); 21772180Sasmodai printf("Random initialise finish\n"); 21872200Sbmilekic mtx_unlock(&Giant); 21965686Smarkm#endif 22065686Smarkm 22165686Smarkm return 0; 22262053Smarkm} 22362053Smarkm 22462053Smarkmvoid 22562765Smarkmrandom_deinit(void) 22662053Smarkm{ 22762765Smarkm#ifdef DEBUG 22872200Sbmilekic mtx_lock(&Giant); 22972180Sasmodai printf("Random deinitialise\n"); 23072200Sbmilekic mtx_unlock(&Giant); 23162765Smarkm#endif 23265686Smarkm 23365686Smarkm /* Deregister the randomness harvesting routine */ 23462765Smarkm random_deinit_harvester(); 23565686Smarkm 23665686Smarkm#ifdef DEBUG 23772200Sbmilekic mtx_lock(&Giant); 23872180Sasmodai printf("Random deinitialise waiting for thread to terminate\n"); 23972200Sbmilekic mtx_unlock(&Giant); 24065686Smarkm#endif 24165686Smarkm 24265686Smarkm /* Command the hash/reseed thread to end and wait for it to finish */ 24372200Sbmilekic mtx_lock(&harvestring.lockout_mtx); 24465686Smarkm random_kthread_control = -1; 24569526Smarkm msleep((void *)&random_kthread_control, &harvestring.lockout_mtx, PUSER, 24667112Smarkm "rndend", 0); 24772200Sbmilekic mtx_unlock(&harvestring.lockout_mtx); 24865686Smarkm 24965686Smarkm#ifdef DEBUG 25072200Sbmilekic mtx_lock(&Giant); 25172180Sasmodai printf("Random deinitialise removing mutexes\n"); 25272200Sbmilekic mtx_unlock(&Giant); 25365686Smarkm#endif 25465686Smarkm 25565686Smarkm /* Remove the mutexes */ 25665686Smarkm mtx_destroy(&random_reseed_mtx); 25769526Smarkm mtx_destroy(&harvestring.lockout_mtx); 25865686Smarkm 25965686Smarkm#ifdef DEBUG 26072200Sbmilekic mtx_lock(&Giant); 26172180Sasmodai printf("Random deinitialise finish\n"); 26272200Sbmilekic mtx_unlock(&Giant); 26365686Smarkm#endif 26462765Smarkm} 26562765Smarkm 26662765Smarkmstatic void 26762765Smarkmreseed(int fastslow) 26862765Smarkm{ 26965686Smarkm /* Interrupt-context stack is a limited resource; make large 27065686Smarkm * structures static. 27163771Smarkm */ 27265686Smarkm static u_char v[TIMEBIN][KEYSIZE]; /* v[i] */ 27365686Smarkm static struct yarrowhash context; 27465686Smarkm u_char hash[KEYSIZE]; /* h' */ 27565686Smarkm u_char temp[KEYSIZE]; 27662053Smarkm int i, j; 27762053Smarkm 27862765Smarkm#ifdef DEBUG 27972200Sbmilekic mtx_lock(&Giant); 28062765Smarkm printf("Reseed type %d\n", fastslow); 28172200Sbmilekic mtx_unlock(&Giant); 28262765Smarkm#endif 28362765Smarkm 28465686Smarkm /* The reseed task must not be jumped on */ 28572200Sbmilekic mtx_lock(&random_reseed_mtx); 28665686Smarkm 28762053Smarkm /* 1. Hash the accumulated entropy into v[0] */ 28862053Smarkm 28965686Smarkm yarrow_hash_init(&context, NULL, 0); 29065686Smarkm /* Feed the slow pool hash in if slow */ 29165686Smarkm if (fastslow == SLOW) 29265686Smarkm yarrow_hash_iterate(&context, 29365686Smarkm &random_state.pool[SLOW].hash, sizeof(struct yarrowhash)); 29462053Smarkm 29565686Smarkm yarrow_hash_iterate(&context, 29665686Smarkm &random_state.pool[FAST].hash, sizeof(struct yarrowhash)); 29762765Smarkm 29863771Smarkm /* 2. Compute hash values for all v. _Supposed_ to be computationally 29963771Smarkm * intensive. 30063771Smarkm */ 30162053Smarkm 30262765Smarkm if (random_state.bins > TIMEBIN) 30362765Smarkm random_state.bins = TIMEBIN; 30462765Smarkm for (i = 1; i < random_state.bins; i++) { 30565686Smarkm yarrow_hash_init(&context, NULL, 0); 30662765Smarkm /* v[i] #= h(v[i-1]) */ 30765686Smarkm yarrow_hash_iterate(&context, v[i - 1], KEYSIZE); 30862765Smarkm /* v[i] #= h(v[0]) */ 30965686Smarkm yarrow_hash_iterate(&context, v[0], KEYSIZE); 31062765Smarkm /* v[i] #= h(i) */ 31165686Smarkm yarrow_hash_iterate(&context, &i, sizeof(int)); 31265686Smarkm /* Return the hashval */ 31365686Smarkm yarrow_hash_finish(&context, v[i]); 31462053Smarkm } 31562053Smarkm 31665686Smarkm /* 3. Compute a new key; h' is the identity function here; 31765686Smarkm * it is not being ignored! 31865686Smarkm */ 31962053Smarkm 32065686Smarkm yarrow_hash_init(&context, NULL, 0); 32165686Smarkm yarrow_hash_iterate(&context, &random_state.key, KEYSIZE); 32265686Smarkm for (i = 1; i < random_state.bins; i++) 32365686Smarkm yarrow_hash_iterate(&context, &v[i], KEYSIZE); 32465686Smarkm yarrow_hash_finish(&context, temp); 32565686Smarkm yarrow_encrypt_init(&random_state.key, temp, KEYSIZE); 32662053Smarkm 32762053Smarkm /* 4. Recompute the counter */ 32862053Smarkm 32962765Smarkm random_state.counter = 0; 33065686Smarkm yarrow_encrypt(&random_state.key, &random_state.counter, temp, 33165686Smarkm sizeof(random_state.counter)); 33262765Smarkm memcpy(&random_state.counter, temp, random_state.counter); 33362053Smarkm 33462765Smarkm /* 5. Reset entropy estimate accumulators to zero */ 33562053Smarkm 33662765Smarkm for (i = 0; i <= fastslow; i++) { 33762765Smarkm for (j = 0; j < ENTROPYSOURCE; j++) { 33865686Smarkm if (random_state.pool[i].source[j].bits > 33965686Smarkm random_state.pool[i].thresh) { 34065686Smarkm random_state.pool[i].source[j].bits = 0; 34165686Smarkm random_state.pool[i].source[j].frac = 0; 34265686Smarkm } 34362765Smarkm } 34462765Smarkm } 34562053Smarkm 34662053Smarkm /* 6. Wipe memory of intermediate values */ 34762053Smarkm 34865686Smarkm memset((void *)v, 0, sizeof(v)); 34965686Smarkm memset((void *)temp, 0, sizeof(temp)); 35065686Smarkm memset((void *)hash, 0, sizeof(hash)); 35162053Smarkm 35265686Smarkm /* 7. Dump to seed file */ 35365686Smarkm /* XXX Not done here yet */ 35462053Smarkm 35565686Smarkm /* Release the reseed mutex */ 35672200Sbmilekic mtx_unlock(&random_reseed_mtx); 35765686Smarkm 35865686Smarkm#ifdef DEBUG 35972200Sbmilekic mtx_lock(&Giant); 36065686Smarkm printf("Reseed finish\n"); 36172200Sbmilekic mtx_unlock(&Giant); 36265686Smarkm#endif 36365686Smarkm 36467112Smarkm if (!random_state.seeded) { 36567112Smarkm random_state.seeded = 1; 36667112Smarkm selwakeup(&random_state.rsel); 36767112Smarkm wakeup(&random_state); 36867112Smarkm } 36967112Smarkm 37062053Smarkm} 37162053Smarkm 37262053Smarkmu_int 37367112Smarkmread_random_real(void *buf, u_int count) 37462053Smarkm{ 37563855Smarkm static u_int64_t genval; 37662053Smarkm static int cur = 0; 37762053Smarkm static int gate = 1; 37862053Smarkm u_int i; 37962053Smarkm u_int retval; 38062053Smarkm 38162875Smarkm /* The reseed task must not be jumped on */ 38272200Sbmilekic mtx_lock(&random_reseed_mtx); 38362875Smarkm 38462053Smarkm if (gate) { 38562053Smarkm generator_gate(); 38662765Smarkm random_state.outputblocks = 0; 38762053Smarkm gate = 0; 38862053Smarkm } 38962765Smarkm if (count >= sizeof(random_state.counter)) { 39062053Smarkm retval = 0; 39162765Smarkm for (i = 0; i < count; i += sizeof(random_state.counter)) { 39262765Smarkm random_state.counter++; 39365686Smarkm yarrow_encrypt(&random_state.key, &random_state.counter, 39465686Smarkm &genval, sizeof(random_state.counter)); 39563855Smarkm memcpy((char *)buf + i, &genval, 39663855Smarkm sizeof(random_state.counter)); 39762765Smarkm if (++random_state.outputblocks >= random_state.gengateinterval) { 39862053Smarkm generator_gate(); 39962765Smarkm random_state.outputblocks = 0; 40062053Smarkm } 40162765Smarkm retval += sizeof(random_state.counter); 40262053Smarkm } 40362053Smarkm } 40462053Smarkm else { 40562053Smarkm if (!cur) { 40662765Smarkm random_state.counter++; 40765686Smarkm yarrow_encrypt(&random_state.key, &random_state.counter, 40865686Smarkm &genval, sizeof(random_state.counter)); 40962053Smarkm memcpy(buf, &genval, count); 41062765Smarkm cur = sizeof(random_state.counter) - count; 41162765Smarkm if (++random_state.outputblocks >= random_state.gengateinterval) { 41262053Smarkm generator_gate(); 41362765Smarkm random_state.outputblocks = 0; 41462053Smarkm } 41562053Smarkm retval = count; 41662053Smarkm } 41762053Smarkm else { 41862053Smarkm retval = cur < count ? cur : count; 41962053Smarkm memcpy(buf, 42063855Smarkm (char *)&genval + 42163855Smarkm (sizeof(random_state.counter) - cur), 42262053Smarkm retval); 42362053Smarkm cur -= retval; 42462053Smarkm } 42562053Smarkm } 42672200Sbmilekic mtx_unlock(&random_reseed_mtx); 42762053Smarkm return retval; 42862053Smarkm} 42962053Smarkm 43063306Smarkmvoid 43163855Smarkmwrite_random(void *buf, u_int count) 43263306Smarkm{ 43363306Smarkm u_int i; 43463306Smarkm 43569168Smarkm /* Break the input up into HARVESTSIZE chunks. 43669168Smarkm * The writer has too much control here, so "estimate" the 43769168Smarkm * the entropy as zero. 43869168Smarkm */ 43967112Smarkm for (i = 0; i < count; i += HARVESTSIZE) { 44069168Smarkm random_harvest_internal(get_cyclecount(), (char *)buf + i, 44169168Smarkm HARVESTSIZE, 0, 0, RANDOM_WRITE); 44263306Smarkm } 44365686Smarkm 44463855Smarkm /* Maybe the loop iterated at least once */ 44563855Smarkm if (i > count) 44667112Smarkm i -= HARVESTSIZE; 44765686Smarkm 44869168Smarkm /* Get the last bytes even if the input length is not 44969168Smarkm * a multiple of HARVESTSIZE. 45069168Smarkm */ 45167112Smarkm count %= HARVESTSIZE; 45263855Smarkm if (count) { 45369526Smarkm random_harvest_internal(get_cyclecount(), (char *)buf + i, 45469526Smarkm count, 0, 0, RANDOM_WRITE); 45563855Smarkm } 45663306Smarkm} 45763306Smarkm 45862765Smarkmstatic void 45962053Smarkmgenerator_gate(void) 46062053Smarkm{ 46162053Smarkm int i; 46265686Smarkm u_char temp[KEYSIZE]; 46362053Smarkm 46462765Smarkm#ifdef DEBUG 46572200Sbmilekic mtx_lock(&Giant); 46662875Smarkm printf("Generator gate\n"); 46772200Sbmilekic mtx_unlock(&Giant); 46862765Smarkm#endif 46962875Smarkm 47062765Smarkm for (i = 0; i < KEYSIZE; i += sizeof(random_state.counter)) { 47162765Smarkm random_state.counter++; 47265686Smarkm yarrow_encrypt(&random_state.key, &random_state.counter, 47365686Smarkm &(temp[i]), sizeof(random_state.counter)); 47462053Smarkm } 47562053Smarkm 47665686Smarkm yarrow_encrypt_init(&random_state.key, temp, KEYSIZE); 47765686Smarkm memset((void *)temp, 0, KEYSIZE); 47862875Smarkm 47965686Smarkm#ifdef DEBUG 48072200Sbmilekic mtx_lock(&Giant); 48165686Smarkm printf("Generator gate finish\n"); 48272200Sbmilekic mtx_unlock(&Giant); 48365686Smarkm#endif 48462053Smarkm} 48562765Smarkm 48663771Smarkm/* Entropy harvesting routine. This is supposed to be fast; do 48763771Smarkm * not do anything slow in here! 48863771Smarkm */ 48962765Smarkm 49062765Smarkmstatic void 49169168Smarkmrandom_harvest_internal(u_int64_t somecounter, void *entropy, u_int count, 49262841Smarkm u_int bits, u_int frac, enum esource origin) 49362765Smarkm{ 49469526Smarkm struct harvest *harvest; 49569526Smarkm int newhead, tail; 49662765Smarkm 49769168Smarkm#ifdef DEBUG1 49872200Sbmilekic mtx_lock(&Giant); 49962765Smarkm printf("Random harvest\n"); 50072200Sbmilekic mtx_unlock(&Giant); 50162765Smarkm#endif 50269526Smarkm if (origin < ENTROPYSOURCE) { 50362765Smarkm 50469526Smarkm /* Add the harvested data to the ring buffer, but 50569526Smarkm * do not block. 50669526Smarkm */ 50772200Sbmilekic if (mtx_trylock(&harvestring.lockout_mtx)) { 50862850Smarkm 50969526Smarkm tail = atomic_load_acq_int(&harvestring.tail); 51069526Smarkm newhead = (harvestring.head + 1) % HARVEST_RING_SIZE; 51162765Smarkm 51269526Smarkm if (newhead != tail) { 51362765Smarkm 51469526Smarkm harvest = &harvestring.data[harvestring.head]; 51562765Smarkm 51669526Smarkm /* toggle the pool for next insertion */ 51769526Smarkm harvest->pool = random_state.which; 51869526Smarkm random_state.which = !random_state.which; 51962765Smarkm 52069526Smarkm /* Stuff the harvested data into the ring */ 52169526Smarkm harvest->somecounter = somecounter; 52269526Smarkm count = count > HARVESTSIZE ? HARVESTSIZE : count; 52369526Smarkm memcpy(harvest->entropy, entropy, count); 52469526Smarkm harvest->size = count; 52569526Smarkm harvest->bits = bits; 52669526Smarkm harvest->frac = frac; 52769526Smarkm harvest->source = origin; 52862765Smarkm 52969526Smarkm /* Bump the ring counter and shake the reseed 53069526Smarkm * process 53169526Smarkm */ 53269526Smarkm harvestring.head = newhead; 53369526Smarkm wakeup(&harvestring.head); 53462765Smarkm 53569526Smarkm } 53672200Sbmilekic mtx_unlock(&harvestring.lockout_mtx); 53769526Smarkm 53869526Smarkm } 53969526Smarkm 54062765Smarkm } 54162765Smarkm} 54269172Smarkm 54369172Smarkm/* Helper routine to perform explicit reseeds */ 54469172Smarkmvoid 54569172Smarkmrandom_reseed(void) 54669172Smarkm{ 54769172Smarkm reseed(FAST); 54869172Smarkm} 549