yarrow.c revision 67112
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 67112 2000-10-14 10:59:56Z markm $ 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> 3562053Smarkm#include <sys/queue.h> 3665686Smarkm#include <sys/kernel.h> 3765686Smarkm#include <sys/kthread.h> 3862053Smarkm#include <sys/libkern.h> 3965686Smarkm#include <sys/malloc.h> 4065686Smarkm#include <sys/proc.h> 4167112Smarkm#include <sys/select.h> 4262053Smarkm#include <sys/random.h> 4362765Smarkm#include <sys/time.h> 4462053Smarkm#include <sys/types.h> 4565712Sjhb#include <sys/unistd.h> 4665686Smarkm#include <machine/mutex.h> 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); 5763855Smarkmstatic void random_harvest_internal(struct timespec *, 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/* Queue holding harvested entropy */ 6565686SmarkmTAILQ_HEAD(harvestqueue, harvest) harvestqueue, 6665686Smarkm initqueue = TAILQ_HEAD_INITIALIZER(harvestqueue); 6765686Smarkm 6865686Smarkm/* These are used to queue harvested packets of entropy. The entropy 6967112Smarkm * buffer size is pretty arbitrary. 7063771Smarkm */ 7165686Smarkmstruct harvest { 7265686Smarkm struct timespec time; /* nanotime for clock jitter */ 7367112Smarkm u_char entropy[HARVESTSIZE]; /* the harvested entropy */ 7465686Smarkm u_int size, bits, frac; /* stats about the entropy */ 7565686Smarkm enum esource source; /* stats about the entropy */ 7665686Smarkm u_int pool; /* which pool this goes into */ 7765686Smarkm TAILQ_ENTRY(harvest) harvest; /* link to next */ 7865686Smarkm}; 7962765Smarkm 8065686Smarkm/* The reseed thread mutex */ 8165856Sjhbstatic struct mtx random_reseed_mtx; 8262765Smarkm 8367112Smarkm/* The entropy harvest mutex, as well as the mutex associated 8467112Smarkm * with the msleep() call during deinit 8567112Smarkm */ 8665856Sjhbstatic struct mtx random_harvest_mtx; 8765686Smarkm 8865686Smarkm/* <0 to end the kthread, 0 to let it run */ 8965686Smarkmstatic int random_kthread_control = 0; 9065686Smarkm 9165686Smarkmstatic struct proc *random_kthread_proc; 9265686Smarkm 9362765Smarkmstatic void 9467112Smarkmrandom_kthread(void *arg /* NOTUSED */) 9562765Smarkm{ 9665686Smarkm int pl, src, overthreshhold[2]; 9765686Smarkm struct harvest *event; 9865686Smarkm struct source *source; 9965686Smarkm#ifdef DEBUG1 10065686Smarkm int queuecount; 10165686Smarkm#endif 10265686Smarkm 10362765Smarkm#ifdef DEBUG 10467112Smarkm printf("At %s, line %d: mtx_owned(&Giant) == %d, mtx_owned(&sched_lock) == %d\n", __FILE__, __LINE__, mtx_owned(&Giant), mtx_owned(&sched_lock)); 10562765Smarkm#endif 10665686Smarkm 10765686Smarkm for (pl = 0; pl < 2; pl++) 10865686Smarkm yarrow_hash_init(&random_state.pool[pl].hash, NULL, 0); 10965686Smarkm 11065686Smarkm for (;;) { 11165686Smarkm 11265686Smarkm if (TAILQ_EMPTY(&harvestqueue)) { 11365686Smarkm 11465686Smarkm /* Sleep for a second to give the system a chance */ 11565686Smarkm mtx_enter(&Giant, MTX_DEF); 11665686Smarkm tsleep(&harvestqueue, PUSER, "rndslp", hz); 11765686Smarkm mtx_exit(&Giant, MTX_DEF); 11865686Smarkm 11965686Smarkm } 12065686Smarkm else { 12165686Smarkm 12265686Smarkm /* Suck the harvested entropy out of the queue and hash 12365686Smarkm * it into the fast and slow pools. 12465686Smarkm */ 12565686Smarkm#ifdef DEBUG1 12665686Smarkm queuecount = 0; 12765686Smarkm#endif 12865712Sjhb while (!TAILQ_EMPTY(&harvestqueue)) { 12965686Smarkm#ifdef DEBUG1 13065686Smarkm queuecount++; 13165686Smarkm#endif 13265686Smarkm mtx_enter(&random_harvest_mtx, MTX_DEF); 13365686Smarkm 13465686Smarkm event = TAILQ_FIRST(&harvestqueue); 13565686Smarkm TAILQ_REMOVE(&harvestqueue, event, harvest); 13665686Smarkm 13765686Smarkm mtx_exit(&random_harvest_mtx, MTX_DEF); 13865686Smarkm 13965686Smarkm source = &random_state.pool[event->pool].source[event->source]; 14065686Smarkm yarrow_hash_iterate(&random_state.pool[event->pool].hash, 14165686Smarkm event->entropy, sizeof(event->entropy)); 14265686Smarkm yarrow_hash_iterate(&random_state.pool[event->pool].hash, 14365686Smarkm &event->time, sizeof(event->time)); 14465686Smarkm source->frac += event->frac; 14565686Smarkm source->bits += event->bits + source->frac/1024; 14665686Smarkm source->frac %= 1024; 14765686Smarkm free(event, M_TEMP); 14865686Smarkm 14965686Smarkm } 15065686Smarkm#ifdef DEBUG1 15165686Smarkm printf("Harvested %d events\n", queuecount); 15265686Smarkm#endif 15365686Smarkm 15465686Smarkm /* Count the over-threshold sources in each pool */ 15565686Smarkm for (pl = 0; pl < 2; pl++) { 15665686Smarkm overthreshhold[pl] = 0; 15765686Smarkm for (src = 0; src < ENTROPYSOURCE; src++) { 15865686Smarkm if (random_state.pool[pl].source[src].bits 15965686Smarkm > random_state.pool[pl].thresh) 16065686Smarkm overthreshhold[pl]++; 16165686Smarkm } 16265686Smarkm } 16365686Smarkm 16465686Smarkm /* if any fast source over threshhold, reseed */ 16565686Smarkm if (overthreshhold[FAST]) 16665686Smarkm reseed(FAST); 16765686Smarkm 16865686Smarkm /* if enough slow sources are over threshhold, reseed */ 16965686Smarkm if (overthreshhold[SLOW] >= random_state.slowoverthresh) 17065686Smarkm reseed(SLOW); 17165686Smarkm 17265686Smarkm } 17365686Smarkm 17465686Smarkm /* Is the thread scheduled for a shutdown? */ 17567112Smarkm if (random_kthread_control != 0) { 17665686Smarkm if (!TAILQ_EMPTY(&harvestqueue)) { 17765686Smarkm#ifdef DEBUG 17865686Smarkm printf("Random cleaning extraneous events\n"); 17965686Smarkm#endif 18065686Smarkm mtx_enter(&random_harvest_mtx, MTX_DEF); 18165686Smarkm TAILQ_FOREACH(event, &harvestqueue, harvest) { 18265686Smarkm TAILQ_REMOVE(&harvestqueue, event, harvest); 18365686Smarkm free(event, M_TEMP); 18465686Smarkm } 18565686Smarkm mtx_exit(&random_harvest_mtx, MTX_DEF); 18665686Smarkm } 18765686Smarkm#ifdef DEBUG 18865686Smarkm printf("Random kthread setting terminate\n"); 18965686Smarkm#endif 19067112Smarkm random_set_wakeup_exit(&random_kthread_control); 19167112Smarkm /* NOTREACHED */ 19265686Smarkm break; 19365686Smarkm } 19465686Smarkm 19565686Smarkm } 19665686Smarkm 19762765Smarkm} 19862765Smarkm 19965686Smarkmint 20062765Smarkmrandom_init(void) 20162053Smarkm{ 20265686Smarkm int error; 20365686Smarkm 20462765Smarkm#ifdef DEBUG 20565686Smarkm printf("Random initialise\n"); 20662765Smarkm#endif 20765686Smarkm 20862765Smarkm random_state.gengateinterval = 10; 20962765Smarkm random_state.bins = 10; 21062765Smarkm random_state.pool[0].thresh = 100; 21162765Smarkm random_state.pool[1].thresh = 160; 21262765Smarkm random_state.slowoverthresh = 2; 21362765Smarkm random_state.which = FAST; 21465686Smarkm 21565686Smarkm harvestqueue = initqueue; 21665686Smarkm 21765686Smarkm /* Initialise the mutexes */ 21865686Smarkm mtx_init(&random_reseed_mtx, "random reseed", MTX_DEF); 21965686Smarkm mtx_init(&random_harvest_mtx, "random harvest", MTX_DEF); 22065686Smarkm 22165686Smarkm /* Start the hash/reseed thread */ 22267112Smarkm error = kthread_create(random_kthread, NULL, 22365712Sjhb &random_kthread_proc, RFHIGHPID, "random"); 22465686Smarkm if (error != 0) 22565686Smarkm return error; 22665686Smarkm 22765686Smarkm /* Register the randomness harvesting routine */ 22867112Smarkm random_init_harvester(random_harvest_internal, read_random_real); 22965686Smarkm 23065686Smarkm#ifdef DEBUG 23165686Smarkm printf("Random initalise finish\n"); 23265686Smarkm#endif 23365686Smarkm 23465686Smarkm return 0; 23562053Smarkm} 23662053Smarkm 23762053Smarkmvoid 23862765Smarkmrandom_deinit(void) 23962053Smarkm{ 24062765Smarkm#ifdef DEBUG 24165686Smarkm printf("Random deinitalise\n"); 24262765Smarkm#endif 24365686Smarkm 24465686Smarkm /* Deregister the randomness harvesting routine */ 24562765Smarkm random_deinit_harvester(); 24665686Smarkm 24765686Smarkm#ifdef DEBUG 24865686Smarkm printf("Random deinitalise waiting for thread to terminate\n"); 24965686Smarkm#endif 25065686Smarkm 25165686Smarkm /* Command the hash/reseed thread to end and wait for it to finish */ 25267112Smarkm mtx_enter(&random_harvest_mtx, MTX_DEF); 25365686Smarkm random_kthread_control = -1; 25467112Smarkm msleep((void *)&random_kthread_control, &random_harvest_mtx, PUSER, 25567112Smarkm "rndend", 0); 25667112Smarkm mtx_exit(&random_harvest_mtx, MTX_DEF); 25765686Smarkm 25865686Smarkm#ifdef DEBUG 25965686Smarkm printf("Random deinitalise removing mutexes\n"); 26065686Smarkm#endif 26165686Smarkm 26265686Smarkm /* Remove the mutexes */ 26365686Smarkm mtx_destroy(&random_reseed_mtx); 26465686Smarkm mtx_destroy(&random_harvest_mtx); 26565686Smarkm 26665686Smarkm#ifdef DEBUG 26765686Smarkm printf("Random deinitalise finish\n"); 26865686Smarkm#endif 26962765Smarkm} 27062765Smarkm 27162765Smarkmstatic void 27262765Smarkmreseed(int fastslow) 27362765Smarkm{ 27465686Smarkm /* Interrupt-context stack is a limited resource; make large 27565686Smarkm * structures static. 27663771Smarkm */ 27765686Smarkm static u_char v[TIMEBIN][KEYSIZE]; /* v[i] */ 27865686Smarkm static struct yarrowhash context; 27965686Smarkm u_char hash[KEYSIZE]; /* h' */ 28065686Smarkm u_char temp[KEYSIZE]; 28162053Smarkm int i, j; 28262053Smarkm 28362765Smarkm#ifdef DEBUG 28462765Smarkm printf("Reseed type %d\n", fastslow); 28562765Smarkm#endif 28662765Smarkm 28765686Smarkm /* The reseed task must not be jumped on */ 28865686Smarkm mtx_enter(&random_reseed_mtx, MTX_DEF); 28965686Smarkm 29062053Smarkm /* 1. Hash the accumulated entropy into v[0] */ 29162053Smarkm 29265686Smarkm yarrow_hash_init(&context, NULL, 0); 29365686Smarkm /* Feed the slow pool hash in if slow */ 29465686Smarkm if (fastslow == SLOW) 29565686Smarkm yarrow_hash_iterate(&context, 29665686Smarkm &random_state.pool[SLOW].hash, sizeof(struct yarrowhash)); 29762053Smarkm 29865686Smarkm yarrow_hash_iterate(&context, 29965686Smarkm &random_state.pool[FAST].hash, sizeof(struct yarrowhash)); 30062765Smarkm 30163771Smarkm /* 2. Compute hash values for all v. _Supposed_ to be computationally 30263771Smarkm * intensive. 30363771Smarkm */ 30462053Smarkm 30562765Smarkm if (random_state.bins > TIMEBIN) 30662765Smarkm random_state.bins = TIMEBIN; 30762765Smarkm for (i = 1; i < random_state.bins; i++) { 30865686Smarkm yarrow_hash_init(&context, NULL, 0); 30962765Smarkm /* v[i] #= h(v[i-1]) */ 31065686Smarkm yarrow_hash_iterate(&context, v[i - 1], KEYSIZE); 31162765Smarkm /* v[i] #= h(v[0]) */ 31265686Smarkm yarrow_hash_iterate(&context, v[0], KEYSIZE); 31362765Smarkm /* v[i] #= h(i) */ 31465686Smarkm yarrow_hash_iterate(&context, &i, sizeof(int)); 31565686Smarkm /* Return the hashval */ 31665686Smarkm yarrow_hash_finish(&context, v[i]); 31762053Smarkm } 31862053Smarkm 31965686Smarkm /* 3. Compute a new key; h' is the identity function here; 32065686Smarkm * it is not being ignored! 32165686Smarkm */ 32262053Smarkm 32365686Smarkm yarrow_hash_init(&context, NULL, 0); 32465686Smarkm yarrow_hash_iterate(&context, &random_state.key, KEYSIZE); 32565686Smarkm for (i = 1; i < random_state.bins; i++) 32665686Smarkm yarrow_hash_iterate(&context, &v[i], KEYSIZE); 32765686Smarkm yarrow_hash_finish(&context, temp); 32865686Smarkm yarrow_encrypt_init(&random_state.key, temp, KEYSIZE); 32962053Smarkm 33062053Smarkm /* 4. Recompute the counter */ 33162053Smarkm 33262765Smarkm random_state.counter = 0; 33365686Smarkm yarrow_encrypt(&random_state.key, &random_state.counter, temp, 33465686Smarkm sizeof(random_state.counter)); 33562765Smarkm memcpy(&random_state.counter, temp, random_state.counter); 33662053Smarkm 33762765Smarkm /* 5. Reset entropy estimate accumulators to zero */ 33862053Smarkm 33962765Smarkm for (i = 0; i <= fastslow; i++) { 34062765Smarkm for (j = 0; j < ENTROPYSOURCE; j++) { 34165686Smarkm if (random_state.pool[i].source[j].bits > 34265686Smarkm random_state.pool[i].thresh) { 34365686Smarkm random_state.pool[i].source[j].bits = 0; 34465686Smarkm random_state.pool[i].source[j].frac = 0; 34565686Smarkm } 34662765Smarkm } 34762765Smarkm } 34862053Smarkm 34962053Smarkm /* 6. Wipe memory of intermediate values */ 35062053Smarkm 35165686Smarkm memset((void *)v, 0, sizeof(v)); 35265686Smarkm memset((void *)temp, 0, sizeof(temp)); 35365686Smarkm memset((void *)hash, 0, sizeof(hash)); 35462053Smarkm 35565686Smarkm /* 7. Dump to seed file */ 35665686Smarkm /* XXX Not done here yet */ 35762053Smarkm 35865686Smarkm /* Release the reseed mutex */ 35965686Smarkm mtx_exit(&random_reseed_mtx, MTX_DEF); 36065686Smarkm 36165686Smarkm#ifdef DEBUG 36265686Smarkm printf("Reseed finish\n"); 36365686Smarkm#endif 36465686Smarkm 36567112Smarkm if (!random_state.seeded) { 36667112Smarkm random_state.seeded = 1; 36767112Smarkm selwakeup(&random_state.rsel); 36867112Smarkm wakeup(&random_state); 36967112Smarkm } 37067112Smarkm 37162053Smarkm} 37262053Smarkm 37362053Smarkmu_int 37467112Smarkmread_random_real(void *buf, u_int count) 37562053Smarkm{ 37663855Smarkm static u_int64_t genval; 37762053Smarkm static int cur = 0; 37862053Smarkm static int gate = 1; 37962053Smarkm u_int i; 38062053Smarkm u_int retval; 38162053Smarkm 38262875Smarkm /* The reseed task must not be jumped on */ 38365686Smarkm mtx_enter(&random_reseed_mtx, MTX_DEF); 38462875Smarkm 38562053Smarkm if (gate) { 38662053Smarkm generator_gate(); 38762765Smarkm random_state.outputblocks = 0; 38862053Smarkm gate = 0; 38962053Smarkm } 39062765Smarkm if (count >= sizeof(random_state.counter)) { 39162053Smarkm retval = 0; 39262765Smarkm for (i = 0; i < count; i += sizeof(random_state.counter)) { 39362765Smarkm random_state.counter++; 39465686Smarkm yarrow_encrypt(&random_state.key, &random_state.counter, 39565686Smarkm &genval, sizeof(random_state.counter)); 39663855Smarkm memcpy((char *)buf + i, &genval, 39763855Smarkm sizeof(random_state.counter)); 39862765Smarkm if (++random_state.outputblocks >= random_state.gengateinterval) { 39962053Smarkm generator_gate(); 40062765Smarkm random_state.outputblocks = 0; 40162053Smarkm } 40262765Smarkm retval += sizeof(random_state.counter); 40362053Smarkm } 40462053Smarkm } 40562053Smarkm else { 40662053Smarkm if (!cur) { 40762765Smarkm random_state.counter++; 40865686Smarkm yarrow_encrypt(&random_state.key, &random_state.counter, 40965686Smarkm &genval, sizeof(random_state.counter)); 41062053Smarkm memcpy(buf, &genval, count); 41162765Smarkm cur = sizeof(random_state.counter) - count; 41262765Smarkm if (++random_state.outputblocks >= random_state.gengateinterval) { 41362053Smarkm generator_gate(); 41462765Smarkm random_state.outputblocks = 0; 41562053Smarkm } 41662053Smarkm retval = count; 41762053Smarkm } 41862053Smarkm else { 41962053Smarkm retval = cur < count ? cur : count; 42062053Smarkm memcpy(buf, 42163855Smarkm (char *)&genval + 42263855Smarkm (sizeof(random_state.counter) - cur), 42362053Smarkm retval); 42462053Smarkm cur -= retval; 42562053Smarkm } 42662053Smarkm } 42765686Smarkm mtx_exit(&random_reseed_mtx, MTX_DEF); 42862053Smarkm return retval; 42962053Smarkm} 43062053Smarkm 43163306Smarkmvoid 43263855Smarkmwrite_random(void *buf, u_int count) 43363306Smarkm{ 43463306Smarkm u_int i; 43563771Smarkm struct timespec timebuf; 43663306Smarkm 43767112Smarkm /* arbitrarily break the input up into HARVESTSIZE chunks */ 43867112Smarkm for (i = 0; i < count; i += HARVESTSIZE) { 43963771Smarkm nanotime(&timebuf); 44067112Smarkm random_harvest_internal(&timebuf, (char *)buf + i, HARVESTSIZE, 0, 0, 44163855Smarkm RANDOM_WRITE); 44263306Smarkm } 44365686Smarkm 44463855Smarkm /* Maybe the loop iterated at least once */ 44563855Smarkm if (i > count) 44667112Smarkm i -= HARVESTSIZE; 44765686Smarkm 44867112Smarkm /* Get the last bytes even if the input length is not a multiple of HARVESTSIZE */ 44967112Smarkm count %= HARVESTSIZE; 45063855Smarkm if (count) { 45163855Smarkm nanotime(&timebuf); 45263855Smarkm random_harvest_internal(&timebuf, (char *)buf + i, count, 0, 0, 45363855Smarkm RANDOM_WRITE); 45463855Smarkm } 45565686Smarkm 45665686Smarkm /* Explicit reseed */ 45763306Smarkm reseed(FAST); 45863306Smarkm} 45963306Smarkm 46062765Smarkmstatic void 46162053Smarkmgenerator_gate(void) 46262053Smarkm{ 46362053Smarkm int i; 46465686Smarkm u_char temp[KEYSIZE]; 46562053Smarkm 46662765Smarkm#ifdef DEBUG 46762875Smarkm printf("Generator gate\n"); 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 48065686Smarkm printf("Generator gate finish\n"); 48165686Smarkm#endif 48262053Smarkm} 48362765Smarkm 48463771Smarkm/* Entropy harvesting routine. This is supposed to be fast; do 48563771Smarkm * not do anything slow in here! 48663771Smarkm */ 48762765Smarkm 48862765Smarkmstatic void 48963855Smarkmrandom_harvest_internal(struct timespec *timep, void *entropy, u_int count, 49062841Smarkm u_int bits, u_int frac, enum esource origin) 49162765Smarkm{ 49265686Smarkm struct harvest *event; 49362765Smarkm 49465686Smarkm#if 0 49562765Smarkm#ifdef DEBUG 49662765Smarkm printf("Random harvest\n"); 49762765Smarkm#endif 49865686Smarkm#endif 49965686Smarkm event = malloc(sizeof(struct harvest), M_TEMP, M_NOWAIT); 50062765Smarkm 50165686Smarkm if (origin < ENTROPYSOURCE && event != NULL) { 50262850Smarkm 50365686Smarkm /* nanotime provides clock jitter */ 50465686Smarkm event->time = *timep; 50562765Smarkm 50665686Smarkm /* the harvested entropy */ 50767112Smarkm count = count > sizeof(event->entropy) 50867112Smarkm ? sizeof(event->entropy) 50965686Smarkm : count; 51065686Smarkm memcpy(event->entropy, entropy, count); 51162765Smarkm 51265686Smarkm event->size = count; 51365686Smarkm event->bits = bits; 51465686Smarkm event->frac = frac; 51565686Smarkm event->source = origin; 51662765Smarkm 51765686Smarkm /* protect the queue from simultaneous updates */ 51865686Smarkm mtx_enter(&random_harvest_mtx, MTX_DEF); 51962765Smarkm 52065686Smarkm /* toggle the pool for next insertion */ 52165686Smarkm event->pool = random_state.which; 52265686Smarkm random_state.which = !random_state.which; 52362765Smarkm 52465686Smarkm TAILQ_INSERT_TAIL(&harvestqueue, event, harvest); 52562765Smarkm 52665686Smarkm mtx_exit(&random_harvest_mtx, MTX_DEF); 52762765Smarkm } 52862765Smarkm} 529