? out
? arch/amd64/conf/RNDVERBOSE
? arch/arm/xscale/.iopaau.c.swp
Index: arch/amd64/include/types.h
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/include/types.h,v
retrieving revision 1.40
diff -u -p -r1.40 types.h
--- arch/amd64/include/types.h	4 Dec 2011 16:24:13 -0000	1.40
+++ arch/amd64/include/types.h	9 Dec 2011 03:59:21 -0000
@@ -95,7 +95,7 @@ typedef	volatile unsigned char		__cpu_si
 #define	__HAVE_RAS
 
 #include "opt_xen.h"
-#if defined(__x86_64__) && !defined(XEN)
+#if defined(__x86_64__) && !defined(XEN) && defined(notdef)
 #define	__HAVE_DIRECT_MAP 1
 #define	__HAVE_MM_MD_DIRECT_MAPPED_IO
 #define	__HAVE_MM_MD_DIRECT_MAPPED_PHYS
Index: conf/files
===================================================================
RCS file: /cvsroot/src/sys/conf/files,v
retrieving revision 1.1032
diff -u -p -r1.1032 files
--- conf/files	19 Nov 2011 22:51:21 -0000	1.1032
+++ conf/files	9 Dec 2011 03:59:23 -0000
@@ -1439,8 +1439,9 @@ file	dev/mm.c
 file	dev/mulaw.c			mulaw			needs-flag
 file	dev/nullcons_subr.c		nullcons		needs-flag
 file	dev/radio.c			radio			needs-flag
-file	dev/rnd.c			rnd			needs-flag
-file	dev/rndpool.c			rnd			needs-flag
+file	dev/rnd.c
+file	dev/rndpool.c
+file	dev/rndpseudo.c			rnd			needs-flag
 file	dev/sequencer.c			sequencer		needs-flag
 file	dev/video.c			video			needs-flag
 file	dev/vnd.c			vnd			needs-flag
Index: crypto/nist_ctr_drbg/nist_ctr_drbg_aes128.h
===================================================================
RCS file: /cvsroot/src/sys/crypto/nist_ctr_drbg/nist_ctr_drbg_aes128.h,v
retrieving revision 1.1
diff -u -p -r1.1 nist_ctr_drbg_aes128.h
--- crypto/nist_ctr_drbg/nist_ctr_drbg_aes128.h	19 Nov 2011 22:51:22 -0000	1.1
+++ crypto/nist_ctr_drbg/nist_ctr_drbg_aes128.h	9 Dec 2011 03:59:23 -0000
@@ -73,8 +73,8 @@ typedef NIST_AES_ENCRYPT_CTX NIST_Key;
  * 10.2 DRBG Mechanism Based on Block Ciphers
  *
  * Table 3 specifies the reseed interval as
- * <= 2^48.  We use 2^32 so we can always be sure it'll fit in an int.
+ * <= 2^48.  We use 2^31 so we can always be sure it'll fit in an int.
  */
-#define NIST_CTR_DRBG_RESEED_INTERVAL   (0xffffffffU)
+#define NIST_CTR_DRBG_RESEED_INTERVAL   (0x7fffffffU)
 
 #endif /* NIST_CTR_DRBG_AES128_H */
Index: dev/rnd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/rnd.c,v
retrieving revision 1.88
diff -u -p -r1.88 rnd.c
--- dev/rnd.c	29 Nov 2011 03:50:31 -0000	1.88
+++ dev/rnd.c	9 Dec 2011 03:59:23 -0000
@@ -118,14 +118,9 @@ kmutex_t			rnd_mtx;
 TAILQ_HEAD(, rndsink)		rnd_sinks;
 
 /*
- * our select/poll queue
- */
-struct selinfo rnd_selq;
-
-/*
  * Memory pool for sample buffers
  */
-static struct pool rnd_mempool;
+static pool_cache_t rnd_mempc;
 
 /*
  * Our random pool.  This is defined here rather than using the general
@@ -159,34 +154,25 @@ static krndsource_t rnd_source_no_collec
 
 struct callout rnd_callout;
 
-void	rndattach(int);
-
-dev_type_open(rndopen);
-dev_type_read(rndread);
-dev_type_write(rndwrite);
-dev_type_ioctl(rndioctl);
-dev_type_poll(rndpoll);
-dev_type_kqfilter(rndkqfilter);
-
-const struct cdevsw rnd_cdevsw = {
-	rndopen, nullclose, rndread, rndwrite, rndioctl,
-	nostop, notty, rndpoll, nommap, rndkqfilter, D_OTHER|D_MPSAFE,
-};
-
-static inline void	rnd_wakeup_readers(void);
+void	      rnd_wakeup_readers(void);
 static inline u_int32_t rnd_estimate_entropy(krndsource_t *, u_int32_t);
 static inline u_int32_t rnd_counter(void);
 static        void	rnd_timeout(void *);
 static	      void	rnd_process_events(void *);
-static u_int32_t	rnd_extract_data_locked(void *, u_int32_t, u_int32_t);
+u_int32_t     rnd_extract_data_locked(void *, u_int32_t, u_int32_t); /* XXX */
 
-static int		rnd_ready = 0;
+int			rnd_ready = 0;
 static int		rnd_have_entropy = 0;
+
+#ifdef DIAGNOSTIC
 static int		rnd_tested = 0;
+static rngtest_t	rnd_rt;
+static uint8_t		rnd_testbits[sizeof(rnd_rt.rt_b)];
+#endif
 
 LIST_HEAD(, krndsource)	rnd_sources;
 
-static rndsave_t	*boot_rsp;
+rndsave_t		*boot_rsp;
 /*
  * Generate a 32-bit counter.  This should be more machine dependent,
  * using cycle counters and the like when possible.
@@ -211,7 +197,7 @@ rnd_counter(void)
 /*
  * Check to see if there are readers waiting on us.  If so, kick them.
  */
-static inline void
+void
 rnd_wakeup_readers(void)
 {
 	rndsink_t *sink, *tsink;
@@ -252,9 +238,7 @@ rnd_wakeup_readers(void)
 			       rndpool_get_entropy_count(&rnd_pool));
 #endif
 		rnd_have_entropy = 1;
-		cv_broadcast(&rndpool_cv);
 		mutex_spin_exit(&rndpool_mtx);
-		selnotify(&rnd_selq, 0, 0);
 	} else {
 		mutex_spin_exit(&rndpool_mtx);
 	}
@@ -324,39 +308,6 @@ rnd_estimate_entropy(krndsource_t *rs, u
 	return (1);
 }
 
-static int
-rnd_mempool_init(void)
-{
-
-	pool_init(&rnd_mempool, sizeof(rnd_sample_t), 0, 0, 0, "rndsample",
-	    NULL, IPL_VM);
-	return 0;
-}
-static ONCE_DECL(rnd_mempoolinit_ctrl);
-
-/*
- * "Attach" the random device. This is an (almost) empty stub, since
- * pseudo-devices don't get attached until after config, after the
- * entropy sources will attach. We just use the timing of this event
- * as another potential source of initial entropy.
- */
-void
-rndattach(int num)
-{
-	u_int32_t c;
-
-	RUN_ONCE(&rnd_mempoolinit_ctrl, rnd_mempool_init);
-
-	/* Trap unwary players who don't call rnd_init() early */
-	KASSERT(rnd_ready);
-
-	/* mix in another counter */
-	c = rnd_counter();
-	mutex_spin_enter(&rndpool_mtx);
-	rndpool_add_data(&rnd_pool, &c, sizeof(u_int32_t), 1);
-	mutex_spin_exit(&rndpool_mtx);
-}
-
 /*
  * initialize the global random pool for our use.
  * rnd_init() must be called very early on in the boot process, so
@@ -384,12 +335,14 @@ rnd_init(void)
 	LIST_INIT(&rnd_sources);
 	SIMPLEQ_INIT(&rnd_samples);
 	TAILQ_INIT(&rnd_sinks);
-	selinit(&rnd_selq);
 
 	rndpool_init(&rnd_pool);
 	mutex_init(&rndpool_mtx, MUTEX_DEFAULT, IPL_VM);
 	cv_init(&rndpool_cv, "rndread");
 
+	rnd_mempc = pool_cache_init(sizeof(rnd_sample_t), 0, 0, 0,
+				    "rndsample", NULL, IPL_VM,
+				    NULL, NULL, NULL);
 	/* Mix *something*, *anything* into the pool to help it get started.
 	 * However, it's not safe for rnd_counter() to call microtime() yet,
 	 * so on some platforms we might just end up with zeros anyway.
@@ -428,496 +381,12 @@ rnd_init(void)
 	}
 }
 
-int
-rndopen(dev_t dev, int flags, int ifmt,
-    struct lwp *l)
-{
-
-	if (rnd_ready == 0)
-		return (ENXIO);
-
-	if (minor(dev) == RND_DEV_URANDOM || minor(dev) == RND_DEV_RANDOM)
-		return (0);
-
-	return (ENXIO);
-}
-
-int
-rndread(dev_t dev, struct uio *uio, int ioflag)
-{
-	u_int8_t *bf;
-	u_int32_t entcnt, mode, n, nread;
-	int ret;
-
-	DPRINTF(RND_DEBUG_READ,
-	    ("Random:  Read of %zu requested, flags 0x%08x\n",
-	    uio->uio_resid, ioflag));
-
-	if (uio->uio_resid == 0)
-		return (0);
-
-	switch (minor(dev)) {
-	case RND_DEV_RANDOM:
-		mode = RND_EXTRACT_GOOD;
-		break;
-	case RND_DEV_URANDOM:
-		mode = RND_EXTRACT_ANY;
-		break;
-	default:
-		/* Can't happen, but this is cheap */
-		return (ENXIO);
-	}
-
-	ret = 0;
-	bf = kmem_alloc(RND_TEMP_BUFFER_SIZE, KM_SLEEP);
-	while (uio->uio_resid > 0) {
-		n = min(RND_TEMP_BUFFER_SIZE, uio->uio_resid);
-
-		/*
-		 * Make certain there is data available.  If there
-		 * is, do the I/O even if it is partial.  If not,
-		 * sleep unless the user has requested non-blocking
-		 * I/O.
-		 *
-		 * If not requesting strong randomness, we can always read.
-		 */
-		mutex_spin_enter(&rndpool_mtx);
-		if (mode != RND_EXTRACT_ANY) {
-			for (;;) {
-				/*
-				 * How much entropy do we have?
-				 * If it is enough for one hash, we can read.
-				 */
-				entcnt = rndpool_get_entropy_count(&rnd_pool);
-				if (entcnt >= RND_ENTROPY_THRESHOLD * 8)
-					break;
-
-				/*
-				 * Data is not available.
-				 */
-				if (ioflag & IO_NDELAY) {
-					mutex_spin_exit(&rndpool_mtx);
-					ret = EWOULDBLOCK;
-					goto out;
-				}
-				ret = cv_wait_sig(&rndpool_cv, &rndpool_mtx);
-				if (ret) {
-					mutex_spin_exit(&rndpool_mtx);
-					goto out;
-				}
-			}
-		}
-		nread = rnd_extract_data_locked(bf, n, mode);
-		mutex_spin_exit(&rndpool_mtx);
-
-		/*
-		 * Copy (possibly partial) data to the user.
-		 * If an error occurs, or this is a partial
-		 * read, bail out.
-		 */
-		ret = uiomove((void *)bf, nread, uio);
-		if (ret != 0 || nread != n)
-			goto out;
-	}
-
-out:
-	kmem_free(bf, RND_TEMP_BUFFER_SIZE);
-	return (ret);
-}
-
-int
-rndwrite(dev_t dev, struct uio *uio, int ioflag)
-{
-	u_int8_t *bf;
-	int n, ret = 0, estimate_ok = 0, estimate = 0, added = 0;
-
-	ret = kauth_authorize_device(curlwp->l_cred,
-	    KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL);
-	if (ret) {
-		return (ret);
-	}
-	estimate_ok = !kauth_authorize_device(curlwp->l_cred,
-	    KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL);
-
-	DPRINTF(RND_DEBUG_WRITE,
-	    ("Random: Write of %zu requested\n", uio->uio_resid));
-
-	if (uio->uio_resid == 0)
-		return (0);
-	ret = 0;
-	bf = kmem_alloc(RND_TEMP_BUFFER_SIZE, KM_SLEEP);
-	while (uio->uio_resid > 0) {
-		/*
-		 * Don't flood the pool.
-		 */
-		if (added > RND_POOLWORDS * sizeof(int)) {
-			printf("rnd: added %d already, adding no more.\n",
-			       added);
-			break;
-		}
-		n = min(RND_TEMP_BUFFER_SIZE, uio->uio_resid);
-
-		ret = uiomove((void *)bf, n, uio);
-		if (ret != 0)
-			break;
-
-		if (estimate_ok) {
-			/*
-			 * Don't cause samples to be discarded by taking
-			 * the pool's entropy estimate to the max.
-			 */
-			if (added > RND_POOLWORDS / 2)
-				estimate = 0;
-			else
-				estimate = n * NBBY / 2;
-			printf("rnd: adding on write, %d bytes, estimate %d\n",
-			       n, estimate);
-		} else {
-			printf("rnd: kauth says no entropy.\n");
-		}
-
-		/*
-		 * Mix in the bytes.
-		 */
-		mutex_spin_enter(&rndpool_mtx);
-		rndpool_add_data(&rnd_pool, bf, n, estimate);
-		mutex_spin_exit(&rndpool_mtx);
-
-		added += n;
-		DPRINTF(RND_DEBUG_WRITE, ("Random: Copied in %d bytes\n", n));
-	}
-	kmem_free(bf, RND_TEMP_BUFFER_SIZE);
-	return (ret);
-}
-
-static void
-krndsource_to_rndsource(krndsource_t *kr, rndsource_t *r)
-{
-	memset(r, 0, sizeof(*r));
-	strlcpy(r->name, kr->name, sizeof(r->name));
-        r->total = kr->total;
-        r->type = kr->type;
-        r->flags = kr->flags;
-}
-
-int
-rndioctl(dev_t dev, u_long cmd, void *addr, int flag,
-    struct lwp *l)
-{
-	krndsource_t *kr;
-	rndstat_t *rst;
-	rndstat_name_t *rstnm;
-	rndctl_t *rctl;
-	rnddata_t *rnddata;
-	u_int32_t count, start;
-	int ret = 0;
-	int estimate_ok = 0, estimate = 0;
-
-	switch (cmd) {
-	case FIONBIO:
-	case FIOASYNC:
-	case RNDGETENTCNT:
-		break;
-
-	case RNDGETPOOLSTAT:
-	case RNDGETSRCNUM:
-	case RNDGETSRCNAME:
-		ret = kauth_authorize_device(l->l_cred,
-		    KAUTH_DEVICE_RND_GETPRIV, NULL, NULL, NULL, NULL);
-		if (ret)
-			return (ret);
-		break;
-
-	case RNDCTL:
-		ret = kauth_authorize_device(l->l_cred,
-		    KAUTH_DEVICE_RND_SETPRIV, NULL, NULL, NULL, NULL);
-		if (ret)
-			return (ret);
-		break;
-
-	case RNDADDDATA:
-		ret = kauth_authorize_device(l->l_cred,
-		    KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL);
-		if (ret)
-			return (ret);
-		estimate_ok = !kauth_authorize_device(l->l_cred,
-		    KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL);
-		break;
-
-	default:
-		return (EINVAL);
-	}
-
-	switch (cmd) {
-
-	/*
-	 * Handled in upper layer really, but we have to return zero
-	 * for it to be accepted by the upper layer.
-	 */
-	case FIONBIO:
-	case FIOASYNC:
-		break;
-
-	case RNDGETENTCNT:
-		mutex_spin_enter(&rndpool_mtx);
-		*(u_int32_t *)addr = rndpool_get_entropy_count(&rnd_pool);
-		mutex_spin_exit(&rndpool_mtx);
-		break;
-
-	case RNDGETPOOLSTAT:
-		mutex_spin_enter(&rndpool_mtx);
-		rndpool_get_stats(&rnd_pool, addr, sizeof(rndpoolstat_t));
-		mutex_spin_exit(&rndpool_mtx);
-		break;
-
-	case RNDGETSRCNUM:
-		rst = (rndstat_t *)addr;
-
-		if (rst->count == 0)
-			break;
-
-		if (rst->count > RND_MAXSTATCOUNT)
-			return (EINVAL);
-
-		/*
-		 * Find the starting source by running through the
-		 * list of sources.
-		 */
-		kr = rnd_sources.lh_first;
-		start = rst->start;
-		while (kr != NULL && start >= 1) {
-			kr = kr->list.le_next;
-			start--;
-		}
-
-		/*
-		 * Return up to as many structures as the user asked
-		 * for.  If we run out of sources, a count of zero
-		 * will be returned, without an error.
-		 */
-		for (count = 0; count < rst->count && kr != NULL; count++) {
-			krndsource_to_rndsource(kr, &rst->source[count]);
-			kr = kr->list.le_next;
-		}
-
-		rst->count = count;
-
-		break;
-
-	case RNDGETSRCNAME:
-		/*
-		 * Scan through the list, trying to find the name.
-		 */
-		rstnm = (rndstat_name_t *)addr;
-		kr = rnd_sources.lh_first;
-		while (kr != NULL) {
-			if (strncmp(kr->name, rstnm->name,
-				    MIN(sizeof(kr->name),
-					sizeof(*rstnm))) == 0) {
-				krndsource_to_rndsource(kr, &rstnm->source);
-				return (0);
-			}
-			kr = kr->list.le_next;
-		}
-
-		ret = ENOENT;		/* name not found */
-
-		break;
-
-	case RNDCTL:
-		/*
-		 * Set flags to enable/disable entropy counting and/or
-		 * collection.
-		 */
-		rctl = (rndctl_t *)addr;
-		kr = rnd_sources.lh_first;
-
-		/*
-		 * Flags set apply to all sources of this type.
-		 */
-		if (rctl->type != 0xff) {
-			while (kr != NULL) {
-				if (kr->type == rctl->type) {
-					kr->flags &= ~rctl->mask;
-					kr->flags |=
-					    (rctl->flags & rctl->mask);
-				}
-				kr = kr->list.le_next;
-			}
-
-			return (0);
-		}
-
-		/*
-		 * scan through the list, trying to find the name
-		 */
-		while (kr != NULL) {
-			if (strncmp(kr->name, rctl->name,
-				    MIN(sizeof(kr->name),
-                                        sizeof(rctl->name))) == 0) {
-				kr->flags &= ~rctl->mask;
-				kr->flags |= (rctl->flags & rctl->mask);
-
-				return (0);
-			}
-			kr = kr->list.le_next;
-		}
-
-		ret = ENOENT;		/* name not found */
-
-		break;
-
-	case RNDADDDATA:
-		/*
-		 * Don't seed twice if our bootloader has
-		 * seed loading support.
-		 */
-		if (!boot_rsp) {
-			rnddata = (rnddata_t *)addr;
-
-			if (rnddata->len > sizeof(rnddata->data))
-				return EINVAL;
-
-			if (estimate_ok) {
-				/*
-				 * Do not accept absurd entropy estimates, and
-				 * do not flood the pool with entropy such that
-				 * new samples are discarded henceforth.
-				 */
-				estimate = MIN((rnddata->len * NBBY) / 2,
-					       MIN(rnddata->entropy,
-						   RND_POOLBITS / 2));
-			} else {
-				estimate = 0;
-			}
-
-			mutex_spin_enter(&rndpool_mtx);
-			rndpool_add_data(&rnd_pool, rnddata->data,
-					 rnddata->len, estimate);
-			mutex_spin_exit(&rndpool_mtx);
-
-			rnd_wakeup_readers();
-		}
-#ifdef RND_VERBOSE
-		else {
-			printf("rnd: already seeded by boot loader\n");
-		}
-#endif
-		break;
-
-	default:
-		return (EINVAL);
-	}
-
-	return (ret);
-}
-
-int
-rndpoll(dev_t dev, int events, struct lwp *l)
-{
-	u_int32_t entcnt;
-	int revents;
-
-	/*
-	 * We are always writable.
-	 */
-	revents = events & (POLLOUT | POLLWRNORM);
-
-	/*
-	 * Save some work if not checking for reads.
-	 */
-	if ((events & (POLLIN | POLLRDNORM)) == 0)
-		return (revents);
-
-	/*
-	 * If the minor device is not /dev/random, we are always readable.
-	 */
-	if (minor(dev) != RND_DEV_RANDOM) {
-		revents |= events & (POLLIN | POLLRDNORM);
-		return (revents);
-	}
-
-	/*
-	 * Make certain we have enough entropy to be readable.
-	 */
-	mutex_spin_enter(&rndpool_mtx);
-	entcnt = rndpool_get_entropy_count(&rnd_pool);
-	mutex_spin_exit(&rndpool_mtx);
-	if (entcnt >= RND_ENTROPY_THRESHOLD * 8)
-		revents |= events & (POLLIN | POLLRDNORM);
-	else
-		selrecord(l, &rnd_selq);
-
-	return (revents);
-}
-
-static void
-filt_rnddetach(struct knote *kn)
-{
-	mutex_spin_enter(&rndpool_mtx);
-	SLIST_REMOVE(&rnd_selq.sel_klist, kn, knote, kn_selnext);
-	mutex_spin_exit(&rndpool_mtx);
-}
-
-static int
-filt_rndread(struct knote *kn, long hint)
-{
-	uint32_t entcnt;
-
-	mutex_spin_enter(&rndpool_mtx);
-	entcnt = rndpool_get_entropy_count(&rnd_pool);
-	mutex_spin_exit(&rndpool_mtx);
-	if (entcnt >= RND_ENTROPY_THRESHOLD * 8) {
-		kn->kn_data = RND_TEMP_BUFFER_SIZE;
-		return (1);
-	}
-	return (0);
-}
-
-static const struct filterops rnd_seltrue_filtops =
-	{ 1, NULL, filt_rnddetach, filt_seltrue };
-
-static const struct filterops rndread_filtops =
-	{ 1, NULL, filt_rnddetach, filt_rndread };
-
-int
-rndkqfilter(dev_t dev, struct knote *kn)
-{
-	struct klist *klist;
-
-	switch (kn->kn_filter) {
-	case EVFILT_READ:
-		klist = &rnd_selq.sel_klist;
-		if (minor(dev) == RND_DEV_URANDOM)
-			kn->kn_fop = &rnd_seltrue_filtops;
-		else
-			kn->kn_fop = &rndread_filtops;
-		break;
-
-	case EVFILT_WRITE:
-		klist = &rnd_selq.sel_klist;
-		kn->kn_fop = &rnd_seltrue_filtops;
-		break;
-
-	default:
-		return (EINVAL);
-	}
-
-	kn->kn_hook = NULL;
-
-	mutex_spin_enter(&rndpool_mtx);
-	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
-	mutex_spin_exit(&rndpool_mtx);
-
-	return (0);
-}
-
 static rnd_sample_t *
 rnd_sample_allocate(krndsource_t *source)
 {
 	rnd_sample_t *c;
 
-	c = pool_get(&rnd_mempool, PR_WAITOK);
+	c = pool_cache_get(rnd_mempc, PR_WAITOK);
 	if (c == NULL)
 		return (NULL);
 
@@ -936,7 +405,7 @@ rnd_sample_allocate_isr(krndsource_t *so
 {
 	rnd_sample_t *c;
 
-	c = pool_get(&rnd_mempool, PR_NOWAIT);
+	c = pool_cache_get(rnd_mempc, PR_NOWAIT);
 	if (c == NULL)
 		return (NULL);
 
@@ -951,7 +420,7 @@ static void
 rnd_sample_free(rnd_sample_t *c)
 {
 	memset(c, 0, sizeof(*c));
-	pool_put(&rnd_mempool, c);
+	pool_cache_put(rnd_mempc, c);
 }
 
 /*
@@ -963,8 +432,6 @@ rnd_attach_source(krndsource_t *rs, cons
 {
 	u_int32_t ts;
 
-	RUN_ONCE(&rnd_mempoolinit_ctrl, rnd_mempool_init);
-
 	ts = rnd_counter();
 
 	strlcpy(rs->name, name, sizeof(rs->name));
@@ -1365,7 +832,7 @@ rnd_timeout(void *arg)
         rnd_process_events(arg);
 }
 
-static u_int32_t
+u_int32_t
 rnd_extract_data_locked(void *p, u_int32_t len, u_int32_t flags)
 {
 
@@ -1381,9 +848,9 @@ rnd_extract_data_locked(void *p, u_int32
 		c = rnd_counter();
 		rndpool_add_data(&rnd_pool, &c, sizeof(u_int32_t), 1);
 	}
-	if (!rnd_tested) {
-		rngtest_t rt;
-		uint8_t testbits[sizeof(rt.rt_b)];
+
+#ifdef DIAGNOSTIC
+	while (!rnd_tested) {
 		int entropy_count;
 
 		entropy_count = rndpool_get_entropy_count(&rnd_pool);
@@ -1391,8 +858,9 @@ rnd_extract_data_locked(void *p, u_int32
 		printf("rnd: starting statistical RNG test, entropy = %d.\n",
 			entropy_count);
 #endif
-		if (rndpool_extract_data(&rnd_pool, rt.rt_b,
-		    sizeof(rt.rt_b), RND_EXTRACT_ANY) != sizeof(rt.rt_b)) {
+		if (rndpool_extract_data(&rnd_pool, rnd_rt.rt_b,
+		    sizeof(rnd_rt.rt_b), RND_EXTRACT_ANY)
+		    != sizeof(rnd_rt.rt_b)) {
 			panic("rnd: could not get bits for statistical test");
 		}
 		/*
@@ -1402,27 +870,30 @@ rnd_extract_data_locked(void *p, u_int32
 		 * up adding back non-random data claiming it were pure
 		 * entropy.
 		 */
-		memcpy(testbits, rt.rt_b, sizeof(rt.rt_b));
-		strlcpy(rt.rt_name, "entropy pool", sizeof(rt.rt_name));
-		if (rngtest(&rt)) {
+		memcpy(rnd_testbits, rnd_rt.rt_b, sizeof(rnd_rt.rt_b));
+		strlcpy(rnd_rt.rt_name, "entropy pool", sizeof(rnd_rt.rt_name));
+		if (rngtest(&rnd_rt)) {
 			/*
 			 * The probabiliity of a Type I error is 3/10000,
 			 * but note this can only happen at boot time.
 			 * The relevant standard says to reset the module,
-			 * so that's what we do.
+			 * but developers objected...
 			 */
-			panic("rnd: entropy pool failed statistical test");
+			printf("rnd: WARNING, ENTROPY POOL FAILED "
+			       "statistical test!\n");
+			continue;
 		}
-		memset(&rt, 0, sizeof(rt));
-		rndpool_add_data(&rnd_pool, testbits, sizeof(testbits),
+		memset(&rnd_rt, 0, sizeof(rnd_rt));
+		rndpool_add_data(&rnd_pool, rnd_testbits, sizeof(rnd_testbits),
 				 entropy_count);
-		memset(testbits, 0, sizeof(testbits));
+		memset(rnd_testbits, 0, sizeof(rnd_testbits));
 #ifdef RND_VERBOSE
 		printf("rnd: statistical RNG test done, entropy = %d.\n",
 		       rndpool_get_entropy_count(&rnd_pool));
 #endif
 		rnd_tested++;
 	}
+#endif
 	return rndpool_extract_data(&rnd_pool, p, len, flags);
 }
 
Index: dev/rndpseudo.c
===================================================================
RCS file: dev/rndpseudo.c
diff -N dev/rndpseudo.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dev/rndpseudo.c	9 Dec 2011 03:59:23 -0000
@@ -0,0 +1,715 @@
+/*	$NetBSD: rndpseudo.c,v 1.87 2011/11/28 07:56:54 tls Exp $	*/
+
+/*-
+ * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Michael Graff <explorer@flame.org> and Thor Lancelot Simon.
+ * This code uses ideas and algorithms from the Linux driver written by
+ * Ted Ts'o.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: rnd.c,v 1.87 2011/11/28 07:56:54 tls Exp $");
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/select.h>
+#include <sys/poll.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/systm.h>
+#include <sys/rnd.h>
+#include <sys/vnode.h>
+#include <sys/pool.h>
+#include <sys/kauth.h>
+#include <sys/cprng.h>
+#include <sys/stat.h>
+
+#include <dev/rnd_private.h>
+
+#if defined(__HAVE_CPU_COUNTER) && !defined(_RUMPKERNEL) /* XXX: bad pooka */
+#include <machine/cpu_counter.h>
+#endif
+
+#ifdef RND_DEBUG
+#define	DPRINTF(l,x)      if (rnd_debug & (l)) printf x
+int	rnd_debug = 0;
+#else
+#define	DPRINTF(l,x)
+#endif
+
+#define	RND_DEBUG_WRITE		0x0001
+#define	RND_DEBUG_READ		0x0002
+#define	RND_DEBUG_IOCTL		0x0004
+#define	RND_DEBUG_SNOOZE	0x0008
+
+/*
+ * list devices attached
+ */
+#if 0
+#define	RND_VERBOSE
+#endif
+
+/*
+ * The size of a temporary buffer, kmem_alloc()ed when needed, and used for
+ * reading and writing data.
+ */
+#define	RND_TEMP_BUFFER_SIZE	512
+
+static pool_cache_t rp_pc;
+static pool_cache_t rp_cpc;
+
+/*
+ * A context.  cprng plus a smidge.
+ */
+typedef struct {
+	cprng_strong_t	*cprng;
+	int		hard;
+} rp_ctx_t;
+
+/*
+ * Our random pool.  This is defined here rather than using the general
+ * purpose one defined in rndpool.c.
+ *
+ * Samples are collected and queued into a separate mutex-protected queue
+ * (rnd_samples, see above), and processed in a timeout routine; therefore,
+ * the mutex protecting the random pool is at IPL_SOFTCLOCK() as well.
+ */
+extern rndpool_t rnd_pool;
+extern kmutex_t  rndpool_mtx;
+
+void	rndattach(int);
+
+dev_type_open(rndopen);
+
+const struct cdevsw rnd_cdevsw = {
+	rndopen, noclose, noread, nowrite, noioctl, nostop,
+	notty, nopoll, nommap, nokqfilter, D_OTHER|D_MPSAFE
+};
+
+static int rnd_read(struct file *, off_t *, struct uio *, kauth_cred_t, int);
+static int rnd_write(struct file *, off_t *, struct uio *, kauth_cred_t, int);
+static int rnd_ioctl(struct file *, u_long, void *);
+static int rnd_poll(struct file *, int);
+static int rnd_stat(struct file *, struct stat *);
+static int rnd_close(struct file *);
+static int rnd_kqfilter(struct file *, struct knote *);
+
+const struct fileops rnd_fileops = {
+	.fo_read = rnd_read,
+	.fo_write = rnd_write,
+	.fo_ioctl = rnd_ioctl,
+	.fo_fcntl = fnullop_fcntl,
+	.fo_poll = rnd_poll,
+	.fo_stat = rnd_stat,
+	.fo_close = rnd_close,
+	.fo_kqfilter = rnd_kqfilter,
+	.fo_restart = fnullop_restart
+};
+
+void			rnd_wakeup_readers(void);	/* XXX */
+extern int		rnd_ready;		/* XXX */
+extern rndsave_t	*boot_rsp;		/* XXX */
+extern LIST_HEAD(, krndsource) rnd_sources;	/* XXX */
+
+/*
+ * Generate a 32-bit counter.  This should be more machine dependent,
+ * using cycle counters and the like when possible.
+ */
+static inline u_int32_t
+rndpseudo_counter(void)
+{
+	struct timeval tv;
+
+#if defined(__HAVE_CPU_COUNTER) && !defined(_RUMPKERNEL) /* XXX: bad pooka */
+	if (cpu_hascounter())
+		return (cpu_counter32());
+#endif
+	microtime(&tv);
+	return (tv.tv_sec * 1000000 + tv.tv_usec);
+}
+
+/*
+ * "Attach" the random device. This is an (almost) empty stub, since
+ * pseudo-devices don't get attached until after config, after the
+ * entropy sources will attach. We just use the timing of this event
+ * as another potential source of initial entropy.
+ */
+void
+rndattach(int num)
+{
+	u_int32_t c;
+
+	/* Trap unwary players who don't call rnd_init() early */
+	KASSERT(rnd_ready);
+
+	rp_pc = pool_cache_init(RND_TEMP_BUFFER_SIZE, 0, 0, 0,
+				"rndtemp", NULL, IPL_NONE,
+				NULL, NULL, NULL);
+	rp_cpc = pool_cache_init(sizeof(rp_ctx_t), 0, 0, 0,
+				 "rndctx", NULL, IPL_NONE,
+				 NULL, NULL, NULL);
+
+	/* mix in another counter */
+	c = rndpseudo_counter();
+	mutex_spin_enter(&rndpool_mtx);
+	rndpool_add_data(&rnd_pool, &c, sizeof(u_int32_t), 1);
+	mutex_spin_exit(&rndpool_mtx);
+}
+
+int
+rndopen(dev_t dev, int flag, int ifmt,
+    struct lwp *l)
+{
+	rp_ctx_t *ctx;
+	file_t *fp;
+	int fd, hard, error = 0;
+
+	switch (minor(dev)) {
+	    case RND_DEV_URANDOM:
+		hard = 0;
+		break;
+	    case RND_DEV_RANDOM:
+		hard = 1;
+		break;
+	    default:
+		return ENXIO;
+	}
+	ctx = pool_cache_get(rp_cpc, PR_WAITOK);
+	ctx->cprng = NULL;
+	ctx->hard = hard;
+	
+	if ((error = fd_allocfile(&fp, &fd)) != 0) {
+	    pool_cache_put(rp_cpc, ctx);
+	    return error;
+	}
+
+	return fd_clone(fp, fd, flag, &rnd_fileops, ctx);
+}
+
+static cprng_strong_t *
+rnd_alloc_cprng(rp_ctx_t *ctx)
+{
+	char personalization_buf[64];
+	struct lwp *l = curlwp;
+	int cflags = ctx->hard ? CPRNG_USE_CV :
+				 CPRNG_INIT_ANY|CPRNG_REKEY_ANY;
+
+	snprintf(personalization_buf, sizeof(personalization_buf),
+		 "%d%llud%p%p%d", l->l_proc->p_pid,
+		 (unsigned long long int)l->l_ncsw, l, l->l_proc,
+		 l->l_cpticks);
+
+	return cprng_strong_create(personalization_buf, IPL_NONE, cflags);
+}
+
+static int
+rnd_read(struct file * fp, off_t *offp, struct uio *uio,
+	  kauth_cred_t cred, int flags)
+{
+	rp_ctx_t *ctx = fp->f_data;
+	u_int8_t *bf;
+	u_int32_t n, nread;
+	int ret;
+
+	DPRINTF(RND_DEBUG_READ,
+	    ("Random:  Read of %zu requested, flags 0x%08x\n",
+	    uio->uio_resid, ioflag));
+
+	if (uio->uio_resid == 0)
+		return (0);
+
+	if (ctx->cprng == NULL) {
+		ctx->cprng = rnd_alloc_cprng(ctx);
+		if (ctx->cprng == NULL) {
+			return EIO;
+		}
+        }
+
+	ret = 0;
+	bf = pool_cache_get(rp_pc, PR_WAITOK);
+	while (uio->uio_resid > 0) {
+		n = MIN(RND_TEMP_BUFFER_SIZE, uio->uio_resid);
+
+		nread = cprng_strong(ctx->cprng, bf, n,
+				     (fp->f_flag & FNONBLOCK) ? FNONBLOCK : 0);
+		if (nread != n) {
+			if (fp->f_flag & FNONBLOCK) {
+				ret = EWOULDBLOCK;
+			} else {
+				ret = EINTR;
+			}
+			goto out;
+		}
+		ret = uiomove((void *)bf, nread, uio);
+		if (ret != 0)
+			goto out;
+	}
+
+out:
+	pool_cache_put(rp_pc, bf);
+	return (ret);
+}
+
+static int
+rnd_write(struct file *fp, off_t *offp, struct uio *uio,
+	   kauth_cred_t cred, int flags)
+{
+	u_int8_t *bf;
+	int n, ret = 0, estimate_ok = 0, estimate = 0, added = 0;
+
+	ret = kauth_authorize_device(cred,
+	    KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL);
+	if (ret) {
+		return (ret);
+	}
+	estimate_ok = !kauth_authorize_device(cred,
+	    KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL);
+
+	DPRINTF(RND_DEBUG_WRITE,
+	    ("Random: Write of %zu requested\n", uio->uio_resid));
+
+	if (uio->uio_resid == 0)
+		return (0);
+	ret = 0;
+	bf = pool_cache_get(rp_pc, PR_WAITOK);
+	while (uio->uio_resid > 0) {
+		/*
+		 * Don't flood the pool.
+		 */
+		if (added > RND_POOLWORDS * sizeof(int)) {
+#ifdef RND_VERBOSE
+			printf("rnd: added %d already, adding no more.\n",
+			       added);
+#endif
+			break;
+		}
+		n = min(RND_TEMP_BUFFER_SIZE, uio->uio_resid);
+
+		ret = uiomove((void *)bf, n, uio);
+		if (ret != 0)
+			break;
+
+		if (estimate_ok) {
+			/*
+			 * Don't cause samples to be discarded by taking
+			 * the pool's entropy estimate to the max.
+			 */
+			if (added > RND_POOLWORDS / 2)
+				estimate = 0;
+			else
+				estimate = n * NBBY / 2;
+#ifdef RND_VERBOSE
+			printf("rnd: adding on write, %d bytes, estimate %d\n",
+			       n, estimate);
+#endif
+		} else {
+#ifdef RND_VERBOSE
+			printf("rnd: kauth says no entropy.\n");
+#endif
+		}
+
+		/*
+		 * Mix in the bytes.
+		 */
+		mutex_spin_enter(&rndpool_mtx);
+		rndpool_add_data(&rnd_pool, bf, n, estimate);
+		mutex_spin_exit(&rndpool_mtx);
+
+		added += n;
+		DPRINTF(RND_DEBUG_WRITE, ("Random: Copied in %d bytes\n", n));
+	}
+	pool_cache_put(rp_pc, bf);
+	return (ret);
+}
+
+static void
+krndsource_to_rndsource(krndsource_t *kr, rndsource_t *r)
+{
+	memset(r, 0, sizeof(*r));
+	strlcpy(r->name, kr->name, sizeof(r->name));
+        r->total = kr->total;
+        r->type = kr->type;
+        r->flags = kr->flags;
+}
+
+int
+rnd_ioctl(struct file *fp, u_long cmd, void *addr)
+{
+	krndsource_t *kr;
+	rndstat_t *rst;
+	rndstat_name_t *rstnm;
+	rndctl_t *rctl;
+	rnddata_t *rnddata;
+	u_int32_t count, start;
+	int ret = 0;
+	int estimate_ok = 0, estimate = 0;
+
+	switch (cmd) {
+	case FIONBIO:
+	case FIOASYNC:
+	case RNDGETENTCNT:
+		break;
+
+	case RNDGETPOOLSTAT:
+	case RNDGETSRCNUM:
+	case RNDGETSRCNAME:
+		ret = kauth_authorize_device(curlwp->l_cred,
+		    KAUTH_DEVICE_RND_GETPRIV, NULL, NULL, NULL, NULL);
+		if (ret)
+			return (ret);
+		break;
+
+	case RNDCTL:
+		ret = kauth_authorize_device(curlwp->l_cred,
+		    KAUTH_DEVICE_RND_SETPRIV, NULL, NULL, NULL, NULL);
+		if (ret)
+			return (ret);
+		break;
+
+	case RNDADDDATA:
+		ret = kauth_authorize_device(curlwp->l_cred,
+		    KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL);
+		if (ret)
+			return (ret);
+		estimate_ok = !kauth_authorize_device(curlwp->l_cred,
+		    KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL);
+		break;
+
+	default:
+		return (EINVAL);
+	}
+
+	switch (cmd) {
+
+	/*
+	 * Handled in upper layer really, but we have to return zero
+	 * for it to be accepted by the upper layer.
+	 */
+	case FIONBIO:
+	case FIOASYNC:
+		break;
+
+	case RNDGETENTCNT:
+		mutex_spin_enter(&rndpool_mtx);
+		*(u_int32_t *)addr = rndpool_get_entropy_count(&rnd_pool);
+		mutex_spin_exit(&rndpool_mtx);
+		break;
+
+	case RNDGETPOOLSTAT:
+		mutex_spin_enter(&rndpool_mtx);
+		rndpool_get_stats(&rnd_pool, addr, sizeof(rndpoolstat_t));
+		mutex_spin_exit(&rndpool_mtx);
+		break;
+
+	case RNDGETSRCNUM:
+		rst = (rndstat_t *)addr;
+
+		if (rst->count == 0)
+			break;
+
+		if (rst->count > RND_MAXSTATCOUNT)
+			return (EINVAL);
+
+		mutex_spin_enter(&rndpool_mtx);
+		/*
+		 * Find the starting source by running through the
+		 * list of sources.
+		 */
+		kr = rnd_sources.lh_first;
+		start = rst->start;
+		while (kr != NULL && start >= 1) {
+			kr = kr->list.le_next;
+			start--;
+		}
+
+		/*
+		 * Return up to as many structures as the user asked
+		 * for.  If we run out of sources, a count of zero
+		 * will be returned, without an error.
+		 */
+		for (count = 0; count < rst->count && kr != NULL; count++) {
+			krndsource_to_rndsource(kr, &rst->source[count]);
+			kr = kr->list.le_next;
+		}
+
+		rst->count = count;
+
+		mutex_spin_exit(&rndpool_mtx);
+		break;
+
+	case RNDGETSRCNAME:
+		/*
+		 * Scan through the list, trying to find the name.
+		 */
+		mutex_spin_enter(&rndpool_mtx);
+		rstnm = (rndstat_name_t *)addr;
+		kr = rnd_sources.lh_first;
+		while (kr != NULL) {
+			if (strncmp(kr->name, rstnm->name,
+				    MIN(sizeof(kr->name),
+					sizeof(*rstnm))) == 0) {
+				krndsource_to_rndsource(kr, &rstnm->source);
+				mutex_spin_exit(&rndpool_mtx);
+				return (0);
+			}
+			kr = kr->list.le_next;
+		}
+		mutex_spin_exit(&rndpool_mtx);
+
+		ret = ENOENT;		/* name not found */
+
+		break;
+
+	case RNDCTL:
+		/*
+		 * Set flags to enable/disable entropy counting and/or
+		 * collection.
+		 */
+		mutex_spin_enter(&rndpool_mtx);
+		rctl = (rndctl_t *)addr;
+		kr = rnd_sources.lh_first;
+
+		/*
+		 * Flags set apply to all sources of this type.
+		 */
+		if (rctl->type != 0xff) {
+			while (kr != NULL) {
+				if (kr->type == rctl->type) {
+					kr->flags &= ~rctl->mask;
+					kr->flags |=
+					    (rctl->flags & rctl->mask);
+				}
+				kr = kr->list.le_next;
+			}
+			mutex_spin_exit(&rndpool_mtx);
+			return (0);
+		}
+
+		/*
+		 * scan through the list, trying to find the name
+		 */
+		while (kr != NULL) {
+			if (strncmp(kr->name, rctl->name,
+				    MIN(sizeof(kr->name),
+                                        sizeof(rctl->name))) == 0) {
+				kr->flags &= ~rctl->mask;
+				kr->flags |= (rctl->flags & rctl->mask);
+				
+				mutex_spin_exit(&rndpool_mtx);
+				return (0);
+			}
+			kr = kr->list.le_next;
+		}
+
+		mutex_spin_exit(&rndpool_mtx);
+		ret = ENOENT;		/* name not found */
+		
+		break;
+
+	case RNDADDDATA:
+		/*
+		 * Don't seed twice if our bootloader has
+		 * seed loading support.
+		 */
+		if (!boot_rsp) {
+			rnddata = (rnddata_t *)addr;
+
+			if (rnddata->len > sizeof(rnddata->data))
+				return EINVAL;
+
+			if (estimate_ok) {
+				/*
+				 * Do not accept absurd entropy estimates, and
+				 * do not flood the pool with entropy such that
+				 * new samples are discarded henceforth.
+				 */
+				estimate = MIN((rnddata->len * NBBY) / 2,
+					       MIN(rnddata->entropy,
+						   RND_POOLBITS / 2));
+			} else {
+				estimate = 0;
+			}
+
+			mutex_spin_enter(&rndpool_mtx);
+			rndpool_add_data(&rnd_pool, rnddata->data,
+					 rnddata->len, estimate);
+			mutex_spin_exit(&rndpool_mtx);
+
+			rnd_wakeup_readers();
+		}
+#ifdef RND_VERBOSE
+		else {
+			printf("rnd: already seeded by boot loader\n");
+		}
+#endif
+		break;
+
+	default:
+		return (EINVAL);
+	}
+
+	return (ret);
+}
+
+static int
+rnd_poll(struct file *fp, int events)
+{
+	int revents;
+	rp_ctx_t *ctx = fp->f_data;
+
+	/*
+	 * We are always writable.
+	 */
+	revents = events & (POLLOUT | POLLWRNORM);
+
+	/*
+	 * Save some work if not checking for reads.
+	 */
+	if ((events & (POLLIN | POLLRDNORM)) == 0)
+		return (revents);
+
+	if (ctx->cprng == NULL) {
+		ctx->cprng = rnd_alloc_cprng(ctx);
+		if (ctx->cprng == NULL) {
+			return EIO;
+		}
+	}
+
+	if (cprng_strong_ready(ctx->cprng)) {
+		revents |= events & (POLLIN | POLLRDNORM);
+	} else {
+		mutex_enter(&ctx->cprng->mtx);
+		selrecord(curlwp, &ctx->cprng->selq);
+		mutex_exit(&ctx->cprng->mtx);
+	}
+
+	return (revents);
+}
+
+static int
+rnd_stat(struct file *fp, struct stat *st)
+{
+	rp_ctx_t *ctx = fp->f_data;
+
+	/* XXX lock, if cprng allocated?  why? */
+	memset(st, 0, sizeof(*st));
+	st->st_dev = makedev(cdevsw_lookup_major(&rnd_cdevsw),
+						 ctx->hard ? RND_DEV_RANDOM :
+						 RND_DEV_URANDOM);
+	/* XXX leave atimespect, mtimespec, ctimespec = 0? */
+
+	st->st_uid = kauth_cred_geteuid(fp->f_cred);
+	st->st_gid = kauth_cred_getegid(fp->f_cred);
+	st->st_mode = S_IFCHR;
+	return 0;
+}
+
+static int
+rnd_close(struct file *fp)
+{
+	rp_ctx_t *ctx = fp->f_data;
+
+	if (ctx->cprng) {
+		cprng_strong_destroy(ctx->cprng);
+	}
+	fp->f_data = NULL;
+	pool_cache_put(rp_cpc, ctx);
+
+	return 0;
+}
+
+static void
+filt_rnddetach(struct knote *kn)
+{
+	cprng_strong_t *c = kn->kn_hook;
+
+	mutex_enter(&c->mtx);
+	SLIST_REMOVE(&c->selq.sel_klist, kn, knote, kn_selnext);
+	mutex_exit(&c->mtx);
+}
+
+static int
+filt_rndread(struct knote *kn, long hint)
+{
+	cprng_strong_t *c = kn->kn_hook;
+
+	if (cprng_strong_ready(c)) {
+		kn->kn_data = RND_TEMP_BUFFER_SIZE;
+		return 1;
+	}
+	return 0;
+}
+
+static const struct filterops rnd_seltrue_filtops =
+	{ 1, NULL, filt_rnddetach, filt_seltrue };
+
+static const struct filterops rndread_filtops =
+	{ 1, NULL, filt_rnddetach, filt_rndread };
+
+static int
+rnd_kqfilter(struct file *fp, struct knote *kn)
+{
+	rp_ctx_t *ctx = fp->f_data;
+	struct klist *klist;
+
+	if (ctx->cprng == NULL) {
+		ctx->cprng = rnd_alloc_cprng(ctx);
+		if (ctx->cprng == NULL) {
+			return EIO;
+		}
+	}
+
+	mutex_enter(&ctx->cprng->mtx);
+	switch (kn->kn_filter) {
+	case EVFILT_READ:
+		klist = &ctx->cprng->selq.sel_klist;
+		kn->kn_fop = &rndread_filtops;
+		break;
+
+	case EVFILT_WRITE:
+		klist = &ctx->cprng->selq.sel_klist;
+		kn->kn_fop = &rnd_seltrue_filtops;
+		break;
+
+	default:
+		mutex_exit(&ctx->cprng->mtx);
+		return EINVAL;
+	}
+
+	kn->kn_hook = ctx->cprng;
+
+	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+
+	mutex_exit(&ctx->cprng->mtx);
+	return (0);
+}
Index: dev/iscsi/iscsi_text.c
===================================================================
RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_text.c,v
retrieving revision 1.2
diff -u -p -r1.2 iscsi_text.c
--- dev/iscsi/iscsi_text.c	29 Nov 2011 03:50:31 -0000	1.2
+++ dev/iscsi/iscsi_text.c	9 Dec 2011 03:59:23 -0000
@@ -1459,7 +1459,7 @@ assemble_security_parameters(connection_
 
 			cprng_strong(kern_cprng,
 				     &state->temp_buf[CHAP_MD5_SIZE],
-				     CHAP_CHALLENGE_LEN + 1);
+				     CHAP_CHALLENGE_LEN + 1, 0);
 			set_key_n(state, K_Auth_CHAP_Identifier,
 					  state->temp_buf[CHAP_MD5_SIZE]);
 			cpar = set_key_s(state, K_Auth_CHAP_Challenge,
Index: dist/pf/netinet/tcp_rndiss.c
===================================================================
RCS file: /cvsroot/src/sys/dist/pf/netinet/tcp_rndiss.c,v
retrieving revision 1.3
diff -u -p -r1.3 tcp_rndiss.c
--- dist/pf/netinet/tcp_rndiss.c	19 Nov 2011 22:51:24 -0000	1.3
+++ dist/pf/netinet/tcp_rndiss.c	9 Dec 2011 03:59:23 -0000
@@ -104,7 +104,7 @@ tcp_rndiss_encrypt(u_int16_t val)
 void
 tcp_rndiss_init(void)
 {
-	cprng_strong(kern_cprng, tcp_rndiss_sbox, sizeof(tcp_rndiss_sbox));
+	cprng_strong(kern_cprng, tcp_rndiss_sbox, sizeof(tcp_rndiss_sbox), 0);
 
 	tcp_rndiss_reseed = time_second + TCP_RNDISS_OUT;
 	tcp_rndiss_msb = tcp_rndiss_msb == 0x8000 ? 0 : 0x8000;
Index: kern/init_sysctl.c
===================================================================
RCS file: /cvsroot/src/sys/kern/init_sysctl.c,v
retrieving revision 1.185
diff -u -p -r1.185 init_sysctl.c
--- kern/init_sysctl.c	20 Nov 2011 01:09:14 -0000	1.185
+++ kern/init_sysctl.c	9 Dec 2011 03:59:24 -0000
@@ -1396,7 +1396,7 @@ sysctl_kern_urnd(SYSCTLFN_ARGS)
 {
 	int v, rv;
 
-	rv = cprng_strong(sysctl_prng, &v, sizeof(v));
+	rv = cprng_strong(sysctl_prng, &v, sizeof(v), 0);
 	if (rv == sizeof(v)) {
 		struct sysctlnode node = *rnode;
 		node.sysctl_data = &v;
Index: kern/subr_cprng.c
===================================================================
RCS file: /cvsroot/src/sys/kern/subr_cprng.c,v
retrieving revision 1.4
diff -u -p -r1.4 subr_cprng.c
--- kern/subr_cprng.c	29 Nov 2011 21:48:22 -0000	1.4
+++ kern/subr_cprng.c	9 Dec 2011 03:59:24 -0000
@@ -72,6 +72,17 @@ cprng_counter(void)
 }
 
 static void
+cprng_strong_sched_reseed(cprng_strong_t *const c)
+{
+	KASSERT(mutex_owned(&c->mtx));
+	if (!(c->reseed_pending)) {
+		c->reseed_pending = 1;
+		c->reseed.len = NIST_BLOCK_KEYLEN_BYTES;
+		rndsink_attach(&c->reseed);
+	}
+}
+
+static void
 cprng_strong_reseed(void *const arg)
 {
 	cprng_strong_t *c = arg;
@@ -91,6 +102,7 @@ cprng_strong_reseed(void *const arg)
 	if (c->flags & CPRNG_USE_CV) {
 		cv_broadcast(&c->cv);
 	}
+	selnotify(&c->selq, 0, 0);
 	mutex_exit(&c->mtx);
 }
 
@@ -99,7 +111,7 @@ cprng_strong_create(const char *const na
 {
 	cprng_strong_t *c;
 	uint8_t key[NIST_BLOCK_KEYLEN_BYTES];
-	int r, getmore = 0;
+	int r, getmore = 0, hard = 0;
 	uint32_t cc;
 
 	c = kmem_alloc(sizeof(*c), KM_NOSLEEP);
@@ -119,6 +131,8 @@ cprng_strong_create(const char *const na
 		cv_init(&c->cv, name);
 	}
 
+	selinit(&c->selq);
+
 	r = rnd_extract_data(key, sizeof(key), RND_EXTRACT_GOOD);
 	if (r != sizeof(key)) {
 		if (c->flags & CPRNG_INIT_ANY) {
@@ -127,7 +141,7 @@ cprng_strong_create(const char *const na
 			rnd_extract_data(key + r, sizeof(key - r),
 					 RND_EXTRACT_ANY);
 		} else {
-			return NULL;
+			hard++;
 		}
 		getmore++;
 	}
@@ -138,46 +152,30 @@ cprng_strong_create(const char *const na
 	}
 
 	if (getmore) {
-		int wr = 0;
-
-		/* Ask for more. */
-		c->reseed_pending = 1;
-		c->reseed.len = sizeof(key);
-		rndsink_attach(&c->reseed);
-		if (c->flags & CPRNG_USE_CV) {
-			mutex_enter(&c->mtx);
-			do {
-				wr = cv_wait_sig(&c->cv, &c->mtx);
-				if (__predict_true(wr == 0)) {
-					break;
-				}
-				if (wr == ERESTART) {
-					continue;
-				} else {
-					cv_destroy(&c->cv);
-					mutex_exit(&c->mtx);
-					mutex_destroy(&c->mtx);
-					kmem_free(c, sizeof(c));
-					return NULL;
-				}
-			} while (1);
-			mutex_exit(&c->mtx);
+		/* Cause readers to wait for rekeying. */
+		if (hard) {
+			c->drbg.reseed_counter =
+			    NIST_CTR_DRBG_RESEED_INTERVAL + 1;
+		} else {
+			c->drbg.reseed_counter =
+			    (NIST_CTR_DRBG_RESEED_INTERVAL / 2) + 1;
 		}
 	}
 	return c;
 }
 
 size_t
-cprng_strong(cprng_strong_t *const c, void *const p, size_t len)
+cprng_strong(cprng_strong_t *const c, void *const p, size_t len, int flags)
 {
 	uint32_t cc = cprng_counter();
-
+#ifdef DEBUG
+	int testfail = 0;
+#endif
 	if (len > CPRNG_MAX_LEN) {	/* XXX should we loop? */
 		len = CPRNG_MAX_LEN;	/* let the caller loop if desired */
 	}
-
 	mutex_enter(&c->mtx);
-again:
+
 	if (nist_ctr_drbg_generate(&c->drbg, p, len, &cc, sizeof(cc))) {
 		/* A generator failure really means we hit the hard limit. */
 		if (c->flags & CPRNG_REKEY_ANY) {
@@ -192,16 +190,15 @@ again:
 				panic("cprng %s: nist_ctr_drbg_reseed "
 				      "failed.", c->name);
 			}
-			if (c->flags & CPRNG_USE_CV) {
-				cv_broadcast(&c->cv);	/* XXX unnecessary? */
-			}
 		} else {
-			if (c->flags & CPRNG_USE_CV) {
+			if (!(flags & FNONBLOCK) && 
+			     (c->flags & CPRNG_USE_CV)) {
 				int wr;
 
+				cprng_strong_sched_reseed(c);
 				do {
-					wr = cv_wait_sig(&c->cv, &c->mtx);	
-					if (wr == EINTR) {
+					wr = cv_wait_sig(&c->cv, &c->mtx);
+					if (wr == ERESTART) {
 						mutex_exit(&c->mtx);
 						return 0;
 					}
@@ -209,49 +206,46 @@ again:
 								len, &cc,
 								sizeof(cc)));
 			} else {
-				mutex_exit(&c->mtx);
-				return 0;
+				len = 0;
 			}
 		}
 	}
 
-#ifdef DIAGNOSTIC
+#ifdef DEBUG
 	/*
 	 * If the generator has just been keyed, perform
 	 * the statistical RNG test.
 	 */
 	if (__predict_false(c->drbg.reseed_counter == 1)) {
-		rngtest_t rt;
+		rngtest_t *rt = kmem_alloc(sizeof(*rt), KM_NOSLEEP);
+
+		if (rt) {
 
-		strncpy(rt.rt_name, c->name, sizeof(rt.rt_name));
+			strncpy(rt->rt_name, c->name, sizeof(rt->rt_name));
 
-		if (nist_ctr_drbg_generate(&c->drbg, rt.rt_b,
-		    sizeof(rt.rt_b), NULL, 0)) {
-			panic("cprng %s: nist_ctr_drbg_generate failed!",
-			      c->name);
+			if (nist_ctr_drbg_generate(&c->drbg, rt->rt_b,
+		  	    sizeof(rt->rt_b), NULL, 0)) {
+				panic("cprng %s: nist_ctr_drbg_generate "
+				      "failed!", c->name);
 		
-		}
-		if (rngtest(&rt)) {
-			printf("cprng %s: failed statistical RNG test.\n",
-			      c->name);
-			c->drbg.reseed_counter =
-			    NIST_CTR_DRBG_RESEED_INTERVAL + 1;
-		}
+			}
+			testfail = rngtest(rt);
 
-		memset(&rt, 0, sizeof(rt));
+			if (testfail) {
+				printf("cprng %s: failed statistical RNG "
+				       "test.\n", c->name);
+				c->drbg.reseed_counter =
+				    NIST_CTR_DRBG_RESEED_INTERVAL + 1;
+				len = 0;
+			}
+			memset(rt, 0, sizeof(*rt));
+			kmem_free(rt, sizeof(*rt));
+		}
 	}
 #endif
 	if (__predict_false(c->drbg.reseed_counter >
 			    (NIST_CTR_DRBG_RESEED_INTERVAL / 2))) {
-		if (!(c->reseed_pending)) {
-			c->reseed_pending = 1;
-			c->reseed.len = NIST_BLOCK_KEYLEN_BYTES;
-			rndsink_attach(&c->reseed);
-		}
-		if (__predict_false(c->drbg.reseed_counter >
-				    NIST_CTR_DRBG_RESEED_INTERVAL))  {
-			goto again;	/* statistical test failure */
-		}
+		cprng_strong_sched_reseed(c);
 	}
 
 	mutex_exit(&c->mtx);
@@ -266,6 +260,7 @@ cprng_strong_destroy(cprng_strong_t *c)
 		KASSERT(!cv_has_waiters(&c->cv));
 		cv_destroy(&c->cv);
 	}
+	seldestroy(&c->selq);
 
 	mutex_destroy(&c->mtx);
 	if (c->reseed_pending) {
@@ -302,6 +297,7 @@ cprng_strong_setflags(cprng_strong_t *co
 			if (c->flags & CPRNG_USE_CV) {
 				cv_broadcast(&c->cv);
 			}
+			selnotify(&c->selq, 0, 0);
 		}
 	}
 	c->flags = flags;
Index: net/if_spppsubr.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_spppsubr.c,v
retrieving revision 1.124
diff -u -p -r1.124 if_spppsubr.c
--- net/if_spppsubr.c	19 Nov 2011 22:51:25 -0000	1.124
+++ net/if_spppsubr.c	9 Dec 2011 03:59:24 -0000
@@ -4298,7 +4298,7 @@ sppp_chap_scr(struct sppp *sp)
 
 	/* Compute random challenge. */
 	ch = (uint32_t *)sp->myauth.challenge;
-	cprng_strong(kern_cprng, ch, clen);
+	cprng_strong(kern_cprng, ch, clen, 0);
 
 	sp->confid[IDX_CHAP] = ++sp->pp_seq[IDX_CHAP];
 
Index: netinet/tcp_subr.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.243
diff -u -p -r1.243 tcp_subr.c
--- netinet/tcp_subr.c	19 Nov 2011 22:51:26 -0000	1.243
+++ netinet/tcp_subr.c	9 Dec 2011 03:59:24 -0000
@@ -2220,7 +2220,7 @@ tcp_new_iss1(void *laddr, void *faddr, u
 	 */
 	if (tcp_iss_gotten_secret == false) {
 		cprng_strong(kern_cprng,
-			     tcp_iss_secret, sizeof(tcp_iss_secret));
+			     tcp_iss_secret, sizeof(tcp_iss_secret), 0);
 		tcp_iss_gotten_secret = true;
 	}
 
Index: rump/dev/lib/librnd/Makefile
===================================================================
RCS file: /cvsroot/src/sys/rump/dev/lib/librnd/Makefile,v
retrieving revision 1.2
diff -u -p -r1.2 Makefile
--- rump/dev/lib/librnd/Makefile	16 Feb 2010 20:42:45 -0000	1.2
+++ rump/dev/lib/librnd/Makefile	9 Dec 2011 03:59:24 -0000
@@ -5,7 +5,7 @@
 
 LIB=	rumpdev_rnd
 
-SRCS=   rnd.c rndpool.c
+SRCS=   rnd.c rndpseudo.c rndpool.c
 
 SRCS+=	component.c
 
Index: rump/librump/rumpkern/cprng_stub.c
===================================================================
RCS file: /cvsroot/src/sys/rump/librump/rumpkern/cprng_stub.c,v
retrieving revision 1.3
diff -u -p -r1.3 cprng_stub.c
--- rump/librump/rumpkern/cprng_stub.c	28 Nov 2011 08:05:07 -0000	1.3
+++ rump/librump/rumpkern/cprng_stub.c	9 Dec 2011 03:59:24 -0000
@@ -59,11 +59,13 @@ cprng_init(void)
 	return;
 }
 
-cprng_strong_t *cprng_strong_create(const char *const name, int ipl, int flags)
+cprng_strong_t *
+cprng_strong_create(const char *const name, int ipl, int flags)
 {
 	cprng_strong_t *c;
 
-	c = kmem_alloc(sizeof(*c), KM_NOSLEEP);
+	/* zero struct to zero counters we won't ever set with no DRBG */
+	c = kmem_zalloc(sizeof(*c), KM_NOSLEEP);
 	if (c == NULL) {
 		return NULL;
 	}
@@ -72,11 +74,13 @@ cprng_strong_t *cprng_strong_create(cons
 	if (c->flags & CPRNG_USE_CV) {
 		cv_init(&c->cv, name);
 	}
+	selinit(&c->selq);
 	return c;
 }
 
 
-size_t cprng_strong(cprng_strong_t *c, void *p, size_t len)
+size_t
+cprng_strong(cprng_strong_t *c, void *p, size_t len, int blocking)
 {
 	mutex_enter(&c->mtx);
 	cprng_fast(p, len);		/* XXX! */
@@ -84,7 +88,8 @@ size_t cprng_strong(cprng_strong_t *c, v
 	return len;
 }
 
-void cprng_strong_destroy(cprng_strong_t *c)
+void
+cprng_strong_destroy(cprng_strong_t *c)
 {
 	mutex_destroy(&c->mtx);
 	cv_destroy(&c->cv);
Index: sys/cprng.h
===================================================================
RCS file: /cvsroot/src/sys/sys/cprng.h,v
retrieving revision 1.2
diff -u -p -r1.2 cprng.h
--- sys/cprng.h	28 Nov 2011 08:05:07 -0000	1.2
+++ sys/cprng.h	9 Dec 2011 03:59:24 -0000
@@ -32,10 +32,12 @@
 #define _CPRNG_H
 
 #include <sys/types.h>
+#include <sys/fcntl.h>
 #include <lib/libkern/libkern.h>
 #include <sys/rnd.h>
 #include <crypto/nist_ctr_drbg/nist_ctr_drbg.h>
 #include <sys/condvar.h>
+#include <sys/select.h>
 
 /*
  * NIST SP800-90 says 2^19 bytes per request for the CTR_DRBG.
@@ -76,13 +78,14 @@ uint64_t cprng_fast64(void);
 #endif
 
 typedef struct _cprng_strong {
-	kmutex_t      mtx;
-	kcondvar_t    cv;
-	NIST_CTR_DRBG drbg;
-	int	      flags;
-	char	      name[16];
-	int	      reseed_pending;
-	rndsink_t     reseed;
+	kmutex_t	mtx;
+	kcondvar_t	cv;
+	struct selinfo	selq;
+	NIST_CTR_DRBG	drbg;
+	int		flags;
+	char		name[16];
+	int		reseed_pending;
+	rndsink_t	reseed;
 } cprng_strong_t;
 
 #define CPRNG_INIT_ANY		0x00000001
@@ -91,7 +94,7 @@ typedef struct _cprng_strong {
 
 cprng_strong_t *cprng_strong_create(const char *const, int, int);
 
-size_t cprng_strong(cprng_strong_t *const, void *const, size_t);
+size_t cprng_strong(cprng_strong_t *const, void *const, size_t, int);
 
 void cprng_strong_destroy(cprng_strong_t *);
 
@@ -101,7 +104,7 @@ static inline uint32_t
 cprng_strong32(void)
 {
 	uint32_t r;
-	cprng_strong(kern_cprng, &r, sizeof(r));
+	cprng_strong(kern_cprng, &r, sizeof(r), 0);
         return r;
 }
 
@@ -109,10 +112,23 @@ static inline uint64_t
 cprng_strong64(void)
 {
         uint64_t r;
-	cprng_strong(kern_cprng, &r, sizeof(r));
+	cprng_strong(kern_cprng, &r, sizeof(r), 0);
         return r;
 }
 
+static inline int
+cprng_strong_ready(cprng_strong_t *c)
+{
+	int ret = 0;
+	
+	mutex_enter(&c->mtx);
+	if (c->drbg.reseed_counter < NIST_CTR_DRBG_RESEED_INTERVAL) {
+		ret = 1;
+	}
+	mutex_exit(&c->mtx);
+	return ret;
+}
+
 void cprng_init(void);
 int cprng_strong_getflags(cprng_strong_t *const);
 void cprng_strong_setflags(cprng_strong_t *const, int);
Index: sys/param.h
===================================================================
RCS file: /cvsroot/src/sys/sys/param.h,v
retrieving revision 1.397
diff -u -p -r1.397 param.h
--- sys/param.h	28 Nov 2011 08:05:07 -0000	1.397
+++ sys/param.h	9 Dec 2011 03:59:24 -0000
@@ -63,7 +63,7 @@
  *	2.99.9		(299000900)
  */
 
-#define	__NetBSD_Version__	599005800	/* NetBSD 5.99.58 */
+#define	__NetBSD_Version__	599005900	/* NetBSD 5.99.59 */
 
 #define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \
     (m) * 1000000) + (p) * 100) <= __NetBSD_Version__)
