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