diff -ruN oskit-20020317/examples/x86/GNUmakerules oskit-20020317-entropy/examples/x86/GNUmakerules
--- oskit-20020317/examples/x86/GNUmakerules	Tue Feb 27 17:35:35 2001
+++ oskit-20020317-entropy/examples/x86/GNUmakerules	Thu Jan  2 11:06:58 2003
@@ -30,7 +30,7 @@
 TARGETS = hello multiboot timer timer_com timer_com2 stream_netio \
 	spf uspf pingreply diskpart diskpart2 blkio tty netbsd_fs_com \
 	netbsd_fs_posix fsread socket_com socket_com2 mouse memtest \
-        memfs_com memfstest1 perfmon anno_test
+	memfs_com memfstest1 perfmon anno_test rndtest rndunittest
 
 all: $(TARGETS)
 
@@ -38,6 +38,7 @@
 
 SRCDIRS +=	$(OSKIT_SRCDIR)/examples/x86 \
 		$(OSKIT_SRCDIR)/examples/x86/more \
+		$(OSKIT_SRCDIR)/examples/x86/entropy \
 		$(OSKIT_SRCDIR)/examples/x86/shared
 INCDIRS +=	$(OSKIT_SRCDIR)/oskit/c	\
 		$(OSKIT_SRCDIR)/examples/x86/shared
@@ -435,4 +436,20 @@
 		-loskit_clientos -loskit_kern -loskit_lmm \
 		$(CLIB) $(OBJDIR)/lib/crtn.o
 
+rndtest: $(OBJDIR)/lib/multiboot.o rndtest.o bootp.o dummy.o $(DEPENDLIBS)
+	$(OSKIT_QUIET_MAKE_INFORM) "Linking example $@"
+	$(LD) -Ttext 100000 $(LDFLAGS) $(OSKIT_LDFLAGS) \
+		-o $@ $(filter-out %.a,$^)		\
+		-loskit_startup -loskit_clientos -loskit_bootp \
+		-loskit_linux_dev -loskit_dev -loskit_kern -loskit_lmm \
+		$(CLIB) $(OBJDIR)/lib/crtn.o
+
+rndunittest: $(OBJDIR)/lib/multiboot.o rndunittest.o bootp.o $(DEPENDLIBS)
+	$(OSKIT_QUIET_MAKE_INFORM) "Linking example $@"
+	$(LD) -Ttext 100000 $(LDFLAGS) $(OSKIT_LDFLAGS) \
+		-o $@ $(filter-out %.a,$^)		\
+		-loskit_startup -loskit_clientos -loskit_bootp \
+		-loskit_linux_dev -loskit_dev -loskit_kern -loskit_lmm \
+		$(CLIB) $(OBJDIR)/lib/crtn.o
+
 endif
diff -ruN oskit-20020317/examples/x86/entropy/rndtest.c oskit-20020317-entropy/examples/x86/entropy/rndtest.c
--- oskit-20020317/examples/x86/entropy/rndtest.c	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/examples/x86/entropy/rndtest.c	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,551 @@
+
+/*
+ * Entropy pool test kernel.  The code that runs the network and disk was
+ * snarfed from other example kernels.
+ */
+
+#include <malloc.h> /* smemalign */
+#include <oskit/types.h>
+#include <oskit/clientos.h>
+#include <oskit/dev/osenv.h>
+#include <oskit/dev/entropy.h>
+#include <oskit/dev/ethernet.h>
+#include <oskit/dev/linux.h>
+#include <oskit/net/ether.h>
+#include <oskit/c/string.h>
+#include <oskit/startup.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "bootp.h"
+#include "netinet.h"
+
+extern oskit_services_t *global_registry;
+extern oskit_services_t *device_registry;
+extern oskit_services_t *driver_registry;
+
+#define MAX_ETHERNET_DEVICES 8		/* max number of ethernet cards */
+
+extern void (*_init_devices_blk)(void);
+
+extern void (*_init_devices_entropy)(void);
+
+int test_block(int, int);
+int read_test(int, int, char *);
+
+oskit_blkio_t *io;
+
+/* These are in terms of SECTORS. */
+int test_offset[] = { 0, 1, 3,  7, 8, 63, 64, 127, 128, 1024, 1025 };
+int test_size[]   = { 1, 2, 5, 11, 8, 63, 64, 128, 129, 333, 1024, 1025 };
+
+#define n_offsets (sizeof(test_offset) / sizeof(test_offset[0]))
+#define n_sizes (sizeof(test_size) / sizeof(test_size[0]))
+
+static int ndev;
+
+struct etherdev {
+	oskit_etherdev_t	*dev;
+	oskit_netio_t	*send_nio;
+	oskit_netio_t	*recv_nio;
+	oskit_devinfo_t	info;
+	unsigned char	haddr[OSKIT_ETHERDEV_ADDR_SIZE];
+	struct in_addr  myip;	/* My IP address in host order. */
+	int		ipbuf[512];
+};
+static struct etherdev devs[MAX_ETHERNET_DEVICES];
+
+static void whoami(int, oskit_etherdev_t *, struct in_addr *);
+oskit_error_t net_receive(void *, oskit_bufio_t *, oskit_size_t);
+static unsigned short ipcksum(void *, int);
+static void swapn(unsigned char [], unsigned char [], int);
+static char *iptoa(unsigned long);
+
+void oskit_dump_drivers(void);
+
+int
+main(int argc, char **argv)
+{
+	oskit_error_t err = 0;
+	oskit_etherdev_t **etherdev_aref;
+	oskit_entropy_t **entropy_aref;
+	oskit_osenv_t *osenv;
+	int i;
+	char name[10];
+	oskit_size_t sec_size;
+	oskit_off_t disk_size;
+	int rc = 0;
+	int n_tests, j;
+	oskit_entropy_stats_t entropy_stats;
+	unsigned int n_calls_1;
+	unsigned int entropy_count_1;
+	unsigned int n_calls_2;
+	unsigned int entropy_count_2;
+
+	/* Must be on little endian machine. */
+	i = 1;
+	assert(*(char *)&i == 1);
+	
+	oskit_clientos_init();
+	osenv = start_osenv();
+
+	/*
+	 * Make it possible to query the device registry.
+	 */
+	osenv_device_registration_init();
+
+	/*
+	 * Initialize Linux devices.
+	 */
+	oskit_dev_init(osenv);
+	oskit_linux_init_osenv(osenv);
+
+	osenv_process_lock();
+	start_devices();
+	osenv_process_unlock();
+
+	/*
+	 * Init the entropy device(s).
+	 */
+	_init_devices_entropy = oskit_linux_init_entropy;
+	(*_init_devices_entropy)();
+	
+	/*
+	 * Init the block devices.
+	 */
+	_init_devices_blk = oskit_linux_init_blk;
+	(*_init_devices_blk)();
+	/**/
+
+	/*
+	 * Start the network.
+	 */
+	/*start_network();*/
+	
+	/*
+	 * Employ frobiscus.
+	 */
+	oskit_dev_probe();
+
+	/*
+	 * Check to see if the entropy device(s are) there.
+	 */
+	ndev = osenv_device_lookup(&oskit_entropy_iid,
+				   (void***)&entropy_aref);
+	if (ndev > 0)
+	{
+	    osenv_log(OSENV_LOG_INFO, "DLD: found entropy device!\n");
+	}
+	else
+	{
+	    osenv_log(OSENV_LOG_INFO, "did not find entropy device!\n");
+	}	    
+
+	/*
+	 * Start the network devices
+	 */
+	start_net_devices();
+	
+	/*
+	 * Find all the Ethernet device nodes.
+	 */
+	osenv_log(OSENV_LOG_INFO, "Looking up enet devices\n");
+	ndev = osenv_device_lookup(&oskit_etherdev_iid,
+				   (void***)&etherdev_aref);
+	if (ndev <= 0)
+		panic("No ethernet adaptors found.");
+	if (ndev > MAX_ETHERNET_DEVICES)
+		panic("Too many Ethernet adaptors found.");
+
+	/*
+	 * Open all the devices and have them hand packets to the OS.
+	 */
+	osenv_log(OSENV_LOG_INFO, "%d Ethernet adaptor%s found:\n", ndev, ndev > 1 ? "s" : "");
+	for (i = 0; i < ndev; i++) {
+		int j;
+
+		err = oskit_etherdev_getinfo(etherdev_aref[i], &devs[i].info);
+		if (err)
+			panic("error getting info from ethercard %d", i);
+
+		oskit_etherdev_getaddr(etherdev_aref[i], devs[i].haddr);
+
+		/* Show information about this adaptor */
+		printf("  %-16s%-40s ", devs[i].info.name,
+			devs[i].info.description
+			? devs[i].info.description : "");
+		for (j = 0; j < 5; j++) 
+		    printf("%02x:", devs[i].haddr[j]);
+		printf("%02x\n", devs[i].haddr[5]);
+
+		/* get the IP address */
+		whoami(i, etherdev_aref[i], &devs[i].myip);
+
+		devs[i].dev = etherdev_aref[i];
+		devs[i].recv_nio = oskit_netio_create(net_receive, &devs[i]);
+		if (devs[i].recv_nio == NULL)
+			panic("unable to create recv_nio");
+
+		err = oskit_etherdev_open(etherdev_aref[i], 0,
+					  devs[i].recv_nio,
+					  &devs[i].send_nio);
+	}
+
+	if (!osenv_intr_enabled()) {
+		printf("Interrupts not enabled! enabling!\n");
+		osenv_intr_enable();
+	}
+
+	/*
+	 * Start the block devices
+	 */
+	_init_devices_blk = oskit_linux_init_blk;
+	(*_init_devices_blk)();
+	oskit_dev_probe();
+
+	for (;;) {
+
+	    do {
+		oskit_entropy_getstats(entropy_aref[0], &entropy_stats);
+		n_calls_1 = entropy_stats.n_calls;
+		entropy_count_1 = entropy_stats.entropy_count;
+		
+#ifndef RNDTEST_INTERACTIVE
+		name[0] = 'h';
+		name[1] = 'd';
+		name[2] = 'a';
+		name[3] = '0';
+		name[4] = '\0';
+#else
+		osenv_log(OSENV_LOG_INFO,
+			  "Start pinging, then enter drive (eg 'hda0') to test, `quit' to exit: ");
+		gets(name);
+#endif
+
+		if (!strcmp(name, "quit")) {
+		    rc = 1;
+		    goto done;
+		}
+
+		if (!strcmp(name, ""))
+		    continue;
+
+		osenv_log(OSENV_LOG_INFO, "Opening disk %s...\n", name);
+		err = oskit_linux_block_open(name, OSKIT_DEV_OPEN_READ, &io);
+
+		if (err) {
+			if (err == OSKIT_E_DEV_NOSUCH_DEV)
+			    osenv_log(OSENV_LOG_INFO,
+				      "disk %s does not exist!\n", name);
+			else	
+			    osenv_log(OSENV_LOG_INFO,
+				      "error %x opening disk %s\n", err, name);
+		}
+		
+	    } while (err);
+
+	    sec_size = oskit_blkio_getblocksize(io);
+	    osenv_log(OSENV_LOG_INFO,
+		      "disk native sectors are %d bytes\n", sec_size);
+
+	    if (oskit_blkio_getsize(io, &disk_size)) {
+		osenv_log(OSENV_LOG_INFO,
+			  "Can't determine disk size...assuming the disk is big enough!\n");
+		disk_size = (test_offset[n_offsets - 1] + 
+			     test_size[n_sizes - 1]) * sec_size;
+	    } else
+		osenv_log(OSENV_LOG_INFO, "size of disk is %d kbytes\n", 
+			  (unsigned int)(disk_size >> 10));
+
+	    n_tests = n_offsets;
+	    osenv_log(OSENV_LOG_INFO, "\nRunning %d tests\n\n", n_tests);
+	    for (i = 0; i < n_tests; i++) {
+		for (j = 0; j < n_sizes; j++) {
+		    if (((test_offset[i] + test_size[j]) * sec_size) <=
+			disk_size) {
+			rc = test_block(test_offset[i] * sec_size, 
+					test_size[j] * sec_size);
+
+			if (rc) {
+			    osenv_log(OSENV_LOG_INFO,
+				      "\nEXITING: errors in the disk tests.\n");
+				
+			    oskit_blkio_release(io);
+			    goto done;
+			}
+		    }
+		}
+	    }
+	    oskit_blkio_release(io);
+
+	    oskit_entropy_getstats(entropy_aref[0], &entropy_stats);
+	    n_calls_2 = entropy_stats.n_calls;
+	    entropy_count_2 = entropy_stats.entropy_count;
+
+	    osenv_log(OSENV_LOG_INFO,
+		      "entropy count 1: %d, call count 1: %d\n",
+		      entropy_count_1, n_calls_1);
+	    osenv_log(OSENV_LOG_INFO,
+		      "entropy count 2: %d, call count 2: %d\n",
+		      entropy_count_2, n_calls_2);
+	}
+
+ done:
+	oskit_entropy_release(entropy_aref[0]);
+	return rc;
+}
+
+int
+read_test(int offset, int size, char *buf)
+{
+	int err, amt;
+
+	err = oskit_blkio_read(io, buf, offset, size, &amt);
+	if (err) {
+	    osenv_log(OSENV_LOG_INFO, "  Read ERROR %08x\n", err);
+	    return(1);
+	}
+
+	return 0;
+}
+
+/*
+ * This runs tests on a bunch of disk blocks.
+ * Generally, these should be an integral multiple of sectors aligned
+ * on a sector boundary.
+ */
+int
+test_block(int offset, int size)
+{
+	char *wbuf;
+
+	/* Allocate memory for the data */
+	wbuf = smemalign(512, size);
+	if (!wbuf) {
+	    osenv_log(OSENV_LOG_INFO, "  can't allocate buf!\n");
+	    _exit(1);
+	}
+	memset(wbuf, 0xA5, size);
+
+	/* Read in blocks from the disk. */
+	if (read_test(offset, size, wbuf))
+		return -1;
+
+	/* release the memory */
+	sfree(wbuf, size);
+	
+	return 0;
+}
+
+/*
+ * Figure out my IP address.
+ */
+static void
+whoami(int ifnum, oskit_etherdev_t *dev, struct in_addr *myip)
+{
+	struct in_addr ip;
+
+	char ipaddr[4*4];			/* nnn.nnn.nnn.nnnz */
+	get_ipinfo(dev, ipaddr, 0, 0, 0);
+	inet_aton(ipaddr, &ip);
+	myip->s_addr = ntohl(ip.s_addr);
+}
+
+oskit_error_t
+net_receive(void *data, oskit_bufio_t *b, oskit_size_t pkt_size)
+{
+	oskit_error_t rval = 0;
+	unsigned char bcastaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	static unsigned char *frame;
+	struct ether_header *eth;
+	oskit_bufio_t *our_buf;
+	int err;
+	struct etherdev *dev = (struct etherdev *)data;
+
+	if (pkt_size > ETH_MAX_PACKET) {
+	    osenv_log(OSENV_LOG_INFO,
+		      "%s: Hey Wally, I caught a big one! -- %d bytes\n",
+		      dev->info.name, pkt_size);
+	    rval = OSKIT_E_DEV_BADPARAM;
+	    goto done;
+	}
+
+	err = oskit_bufio_map(b, (void **)&frame, 0, pkt_size);
+	assert(err == 0);
+
+	eth  = (struct ether_header *)frame;
+
+	if (memcmp(eth->ether_dhost, &dev->haddr, sizeof dev->haddr) != 0
+	    && memcmp(eth->ether_dhost, bcastaddr, sizeof bcastaddr) != 0) 
+		goto done;			/* not for me */
+
+	switch (ntohs(eth->ether_type)) {
+	case ETHERTYPE_IP: {
+		static int ipid = 0xb;		/* something random */
+		/*static int count = 0;*/
+		struct ip *ip;
+		int hlen;
+		struct in_addr hin;
+		struct icmp *icmp;
+
+		/* XXX deal with fragments. */
+
+		ip = (struct ip *)(frame + sizeof(struct ether_header));
+		hlen = ip->ip_hl << 2;
+
+		/*
+		 * Copy out from ip header on to ensure proper alignment
+		 * on machines that are not byte addressable!
+		 */
+		memcpy(dev->ipbuf,
+		       frame + sizeof(struct ether_header),
+		       ntohs(ip->ip_len));
+		ip = (struct ip *) dev->ipbuf;
+
+		hin.s_addr = ntohl(ip->ip_src.s_addr);
+		if (ipcksum(ip, hlen) != 0 || ip->ip_p != IPPROTO_ICMP)
+			goto done;		/* bad cksum or not IP */
+
+		icmp = (struct icmp *)((char *)ip + hlen);
+		if (icmp->icmp_type != ICMP_ECHO
+		    || ipcksum(icmp, ntohs(ip->ip_len) - hlen) != 0)
+			goto done;	       /* bad cksum or not ICMP_ECHO */
+
+		/* Send the reply. */
+		icmp->icmp_type = ICMP_ECHOREPLY;
+		/* Another optimization.  Only the icmp type field in the reply
+		 * changes, so we can use this apriori knowledge to determine
+		 * the new checksum based upon the old checksum.  Eliminates
+		 * touching all of the data in the packet once more */
+		if (icmp->icmp_cksum >= 65527)
+			icmp->icmp_cksum += (unsigned short) 9;
+		else
+			icmp->icmp_cksum += (unsigned short) 8;
+
+		ip->ip_id = htons(ipid++);
+
+		/*
+		 * We can't just swap the addresses,
+		 * since broadcast packets didn't come to our address.
+		 */
+		ip->ip_dst = ip->ip_src;
+		ip->ip_src.s_addr = htonl(dev->myip.s_addr);
+
+		ip->ip_sum = 0;
+		ip->ip_sum = ipcksum(ip, hlen);
+
+		swapn(eth->ether_dhost, eth->ether_shost,
+		      sizeof eth->ether_shost);
+
+		/*
+		 * Copy data back into original data buffer.
+		 */
+		memcpy(frame + sizeof(struct ether_header),
+		       ip, ntohs(ip->ip_len));
+
+		/* Removed this code because it's an unnecessary copy.
+		 * We're already violating the semantics of the push
+		 * by editing the data pushed to us _before_ we copy,
+		 * so this copy is extraneous
+		 */
+		oskit_netio_push(dev->send_nio, b, pkt_size);
+
+		break;
+	}
+	case ETHERTYPE_ARP: {
+		struct arphdr *arp;
+		struct in_addr ip;
+
+		arp = (struct arphdr *)(frame + sizeof(struct ether_header));
+		ip.s_addr = ntohl(*(unsigned long *)arp->ar_tpa);
+
+		if (ntohs(arp->ar_hrd) != ARPHRD_ETHER
+		    || ntohs(arp->ar_pro) != ETHERTYPE_IP
+		    || ntohs(arp->ar_op) != ARPOP_REQUEST
+		    || ip.s_addr != dev->myip.s_addr)
+			goto done;		/* wrong proto or addr */
+
+		/* Send the reply. */
+		arp->ar_op = htons(ARPOP_REPLY);
+		swapn(arp->ar_spa, arp->ar_tpa, sizeof arp->ar_tpa);
+		swapn(arp->ar_sha, arp->ar_tha, sizeof arp->ar_tha);
+		memcpy(arp->ar_sha, dev->haddr, sizeof dev->haddr);
+
+		/* Fill in the ethernet addresses. */
+		bcopy(&eth->ether_shost, &eth->ether_dhost,
+		      sizeof(dev->haddr));
+		bcopy(&dev->haddr, &eth->ether_shost, sizeof(dev->haddr));
+
+		our_buf = oskit_bufio_create(pkt_size);
+		if (b != NULL) {
+			oskit_size_t got;
+
+			oskit_bufio_write(our_buf, frame, 0, pkt_size, &got);
+			assert(got == pkt_size);
+			oskit_netio_push(dev->send_nio, our_buf, pkt_size);
+			oskit_bufio_release(our_buf);
+		} else {
+			osenv_log(OSENV_LOG_INFO,
+				  "couldn't allocate bufio for ARP reply\n");
+		}
+
+		osenv_log(OSENV_LOG_INFO, "%s: sent ARP reply to %s\n",
+			  dev->info.name,
+			  iptoa(*(unsigned long *)arp->ar_tpa));
+		break;
+	}
+	default:
+		break;
+	}
+
+done:
+	return rval;
+}
+
+static unsigned short
+ipcksum(void *buf, int nbytes)
+{
+	unsigned long sum;
+
+	sum = 0;
+	while (nbytes > 1) {
+		sum += *(unsigned short *)buf;
+		buf += 2;
+		nbytes -= 2;
+	}
+	/* Add in odd byte if any. */
+	if (nbytes == 1)
+		sum += *(char *)buf;
+
+	sum = (sum >> 16) + (sum & 0xffff);     /* hi + lo */
+	sum += (sum >> 16);                     /* add carry, if any */
+
+	return (~sum);
+}
+
+static void
+swapn(unsigned char a[], unsigned char b[], int n)
+{
+	int i;
+	unsigned char t[n];
+
+	for (i = 0; i < n; i++) {
+		t[i] = a[i];
+		a[i] = b[i];
+		b[i] = t[i];
+	}
+}
+
+/* The address we are passed is in network order. */
+static char *
+iptoa(unsigned long x)
+{
+	static char buf[4*4];		/* nnn.nnn.nnn.nnnz */
+	unsigned char *p = (unsigned char *)&x;
+
+	sprintf(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+	return buf;
+}
+
+/* End of rndtest.c */
diff -ruN oskit-20020317/examples/x86/entropy/rndunittest.c oskit-20020317-entropy/examples/x86/entropy/rndunittest.c
--- oskit-20020317/examples/x86/entropy/rndunittest.c	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/examples/x86/entropy/rndunittest.c	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,428 @@
+
+/*
+ * Entropy device unit tests.
+ */
+
+#include <malloc.h> /* smemalign */
+#include <oskit/types.h>
+#include <oskit/clientos.h>
+#include <oskit/dev/linux.h>
+#include <oskit/dev/osenv.h>
+#include <oskit/dev/entropy.h>
+#include <oskit/c/string.h>
+#include <oskit/startup.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+extern void (*_init_devices_entropy)(void);
+
+int
+main(int argc, char **argv)
+{
+    oskit_osenv_t *osenv;
+    int rc = 0;
+
+    oskit_clientos_init();
+    osenv = start_osenv();
+
+    /*
+     * Make it possible to query the device registry.
+     */
+    osenv_device_registration_init();
+    
+    /*
+     * Initialize Linux devices.
+     */
+    oskit_dev_init(osenv);
+    oskit_linux_init_osenv(osenv);
+
+    osenv_process_lock();
+    start_devices();
+    osenv_process_unlock();
+    
+    /*
+     * Init for entropy device(s).
+     */
+    _init_devices_entropy = oskit_linux_init_entropy;
+    (*_init_devices_entropy)();
+    
+    /*
+     * Set in ta' Probin'
+     */
+    oskit_dev_probe();
+
+	
+    /*============================================================
+      
+      The first bunch of tests exercise the bottom half of the
+      entropy pool as its used from a device standpoint.  We get
+      it from the device registry and run through each of the
+      interfaces.
+
+      The second bunch exercise the top half of the entropy pool.
+
+      ============================================================ */
+    
+    {
+	int n_entropy_dev;
+	oskit_entropy_t **entropy_aref;
+	
+	/* Lookup the entropy interface via the device registry...
+	 */
+	n_entropy_dev = osenv_device_lookup(&oskit_entropy_iid,
+					    (void***)&entropy_aref);
+	    
+	osenv_log(OSENV_LOG_INFO,
+		  "DLD: found %d entropy device(s):\n", n_entropy_dev);
+	{
+	    int i;
+	    for (i = 0; i < n_entropy_dev; i++)
+	    {
+		osenv_log(OSENV_LOG_INFO,
+			  "DLD:   entropy dev %d at %p\n", i, entropy_aref[i]);
+	    
+		/* Test the iunknown interface...
+		 */	
+		{
+		    oskit_iunknown_t *iunknown;
+		    oskit_entropy_t *ent;
+
+		    oskit_entropy_query(entropy_aref[i],
+					&oskit_iunknown_iid,
+					(void**)&iunknown);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: iunknown is %p\n", iunknown);
+		    assert(entropy_aref[i] == iunknown);
+		    
+		    oskit_iunknown_query(iunknown,
+					 &oskit_entropy_iid,
+					 (void**)&ent);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: entropy from iunknown is %p\n", ent);
+		    assert(iunknown == ent);
+
+		    oskit_entropy_release(ent);
+		    oskit_iunknown_release(iunknown);
+		}
+	
+		/*
+		 * Test the device interface...
+		 */
+		{
+		    oskit_device_t *device;
+		    oskit_entropy_t *ent;
+		    oskit_devinfo_t info;
+		    oskit_driver_t *driver;
+
+		    oskit_entropy_query(entropy_aref[i],
+					&oskit_device_iid,
+					(void**)&device);
+		    osenv_log(OSENV_LOG_INFO, "DLD: device is %p\n", device);
+		    assert(entropy_aref[i] == device);
+		    
+		    oskit_device_query(device,
+				       &oskit_entropy_iid,
+				       (void**)&ent);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: entropy from device is %p\n", ent);
+		    assert(device == ent);
+
+		    /* Test the getinfo call
+		    */
+		    oskit_device_getinfo(device, &info);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD:        device info.name is: %s\n",
+			      info.name);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: device info.description is: %s\n",
+			      info.description);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD:      device info.vendor is: %s\n",
+			      info.vendor);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD:     device info.version is: %s\n",
+			      info.version);
+		    /* Note: info has automatic storage class */
+
+		    /* Test the getdriver call
+		    */
+		    oskit_device_getdriver(device, &driver);
+		    oskit_driver_getinfo(driver, &info);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD:        driver info.name is: %s\n",
+			      info.name);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: driver info.description is: %s\n",
+			      info.description);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD:      driver info.vendor is: %s\n",
+			      info.vendor);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD:     driver info.version is: %s\n",
+			      info.version);
+		    
+		    oskit_entropy_release(ent);
+		    oskit_device_release(device);
+		    oskit_driver_release(driver);
+		}
+		
+		/*
+		 * Test the driver interface...
+		 */	
+		{
+		    oskit_driver_t *driver;
+		    oskit_entropy_t *ent;
+		    oskit_devinfo_t info;
+		    
+		    oskit_entropy_query(entropy_aref[i],
+					&oskit_driver_iid,
+					(void**)&driver);
+		    osenv_log(OSENV_LOG_INFO, "DLD: driver is %p\n", driver);
+		    assert(entropy_aref[i] == driver);
+
+		    oskit_driver_query(driver,
+				       &oskit_entropy_iid,
+				       (void**)&ent);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: entropy from driver is %p\n", ent);
+		    assert(driver == ent);
+		    
+		    oskit_driver_getinfo(driver, &info);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD:        driver(2) info.name is: %s\n",
+			      info.name);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: driver(2) info.description is: %s\n",
+			      info.description);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD:      driver(2) info.vendor is: %s\n",
+			      info.vendor);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD:     driver(2) info.version is: %s\n",
+			      info.version);
+
+		    oskit_entropy_release(ent);
+		    oskit_driver_release(driver);
+		}
+
+		/*
+		 * Test the entropy interface...
+		 */	
+		{
+		    oskit_entropy_stats_t stats;
+		    unsigned int n_calls_1;
+		    unsigned int entropy_count_1;
+		    unsigned int n_calls_2;
+		    unsigned int entropy_count_2;
+		    oskit_entropy_channel_t *channel;
+
+		    /* Get stats */
+		    
+		    /* FIXME: I like this mem scheme better b/c there is not
+		       a reference returned that the caller could corrupt.  But
+		       I think the getinfo call is established already, so I
+		       wonder if this shouldnt parrot that?
+		    */
+		    oskit_entropy_getstats(entropy_aref[i], &stats);
+		    n_calls_1 = stats.n_calls;
+		    entropy_count_1 = stats.entropy_count;
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: stats n_calls is %d entropy_count is %d\n",
+			      n_calls_1, entropy_count_1);
+		    
+		    oskit_entropy_getstats(entropy_aref[i], &stats);
+		    n_calls_2 = stats.n_calls;
+		    entropy_count_2 = stats.entropy_count;
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: stats n_calls is %d entropy_count is %d\n",
+			      n_calls_2, entropy_count_2);
+
+		    assert(n_calls_1 == 1);
+		    assert(n_calls_2 == n_calls_1 + 1);
+
+		    /*
+		      assert(entropy_count_1 == 0);
+		      assert(entropy_count_1 == entropy_count_2);
+		    */
+		    
+		    /* Attach & detach */
+
+		    oskit_entropy_attach_source(entropy_aref[i],
+						"unittest", 0, 0, &channel);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: entropy chan is %p\n", channel);
+		    {
+			/* Use the channel */
+			unsigned int n_calls_1;
+			unsigned int entropy_count_1;
+			unsigned int n_calls_2;
+			unsigned int entropy_count_2;
+
+			/* Check out the query interface */
+			{
+			    oskit_iunknown_t *iunknown;
+			    oskit_entropy_channel_query(channel,
+							&oskit_iunknown_iid,
+							(void**)&iunknown);
+			    osenv_log(OSENV_LOG_INFO,
+				      "DLD: entropy chan iunknown is %p\n",
+				      iunknown);
+			    oskit_iunknown_release(iunknown);
+			}
+
+			/* Get some starting statistics. */
+			{
+			    oskit_entropy_stats_t stats;
+			    oskit_entropy_channel_get_stats(channel, &stats);
+			    n_calls_1 = stats.n_calls;
+			    entropy_count_1 = stats.entropy_count;
+			    osenv_log(OSENV_LOG_INFO,
+				      "DLD: (channel) stats n_calls is %d entropy_count is %d\n",
+				      n_calls_1, entropy_count_1);
+			}
+
+			/* Add some entropy. */
+			{
+			    unsigned int foo = 42;
+			    oskit_entropy_channel_add_data(channel,
+							   (void*)&foo,
+							   sizeof(foo), 3);
+			}
+
+			/* Get statistics to compare to starting statistics. */
+			{
+			    oskit_entropy_stats_t stats;
+			    oskit_entropy_channel_get_stats(channel, &stats);
+			    n_calls_2 = stats.n_calls;
+			    entropy_count_2 = stats.entropy_count;
+			    osenv_log(OSENV_LOG_INFO,
+				      "DLD: (channel) stats n_calls is %d entropy_count is %d\n",
+				      n_calls_2, entropy_count_2);
+			}
+
+			/* Make sure we get what we expect. */
+			assert(n_calls_2 == n_calls_1 + 1);
+			assert(entropy_count_2 > entropy_count_1);
+		    }
+
+		    oskit_entropy_channel_release(channel);		    
+		}
+
+		/*
+		 * Use the non-blocking entropy stream.
+		 */
+		{
+		    oskit_stream_t *stream;
+		    oskit_u32_t actual_num_bytes;
+		    unsigned char entropy_bytes[2];
+		    oskit_entropy_stats_t stats;
+		    unsigned int n_calls_1;
+		    unsigned int entropy_count_1;
+		    unsigned int n_calls_2;
+		    unsigned int entropy_count_2;
+		    unsigned int n_calls_3;
+		    unsigned int entropy_count_3;
+
+		    oskit_entropy_getstats(entropy_aref[i], &stats);
+		    n_calls_1 = stats.n_calls;
+		    entropy_count_1 = stats.entropy_count;
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: stats n_calls is %d entropy_count is %d\n",
+			      n_calls_1, entropy_count_1);
+		    
+		    oskit_entropy_open_nonblocking(entropy_aref[i], &stream);
+		    oskit_stream_write(stream,
+				       (const void*)"Anya V. Skaletskaya",
+				       19, &actual_num_bytes);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: used oskit_stream_write from open_nonblocking\n");
+		    
+		    oskit_entropy_getstats(entropy_aref[i], &stats);
+		    n_calls_2 = stats.n_calls;
+		    entropy_count_2 = stats.entropy_count;
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: stats n_calls is %d entropy_count is %d\n",
+			      n_calls_2, entropy_count_2);
+
+		    oskit_stream_read(stream, (void*)entropy_bytes,
+				      2, &actual_num_bytes);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: read entropy bytes %x and %x\n",
+			      entropy_bytes[0], entropy_bytes[1]);
+		    
+		    oskit_entropy_getstats(entropy_aref[i], &stats);
+		    n_calls_3 = stats.n_calls;
+		    entropy_count_3 = stats.entropy_count;
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: stats n_calls is %d entropy_count is %d\n",
+			      n_calls_3, entropy_count_3);
+		    
+		    oskit_stream_release(stream);
+		}
+
+		/*
+		 * Open the good stream.
+		 */
+		{
+		    oskit_stream_t *stream;
+		    oskit_asyncio_t *asyncio;
+		    oskit_u32_t actual_num_bytes;
+		    oskit_error_t mask;
+		    oskit_error_t readable;
+		    oskit_entropy_stats_t stats;
+		    unsigned int n_calls;
+		    unsigned int entropy_count;
+		    
+		    oskit_entropy_open_good(entropy_aref[i],
+					    &stream, &asyncio);
+		    mask = oskit_asyncio_poll(asyncio);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: poll returned mask (or error) %x (%d)\n",
+			      mask, mask);
+
+		    readable = oskit_asyncio_readable(asyncio);
+		    osenv_log(OSENV_LOG_INFO, "DLD: readable returned %d\n",
+			      readable);
+
+		    oskit_stream_write(stream,
+				       (const void*)"ayakstelaks ayna",
+				       16, &actual_num_bytes);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: (1) used oskit_stream_write from open_good\n");
+
+		    readable = oskit_asyncio_readable(asyncio);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: (1) readable returned %d\n", readable);
+		    
+		    oskit_stream_write(stream,
+				       (const void*)"avokaluk aytak",
+				       14, &actual_num_bytes);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: (2) used oskit_stream_write from open_good\n");
+
+		    readable = oskit_asyncio_readable(asyncio);
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: (2) readable returned %d\n", readable);
+		    
+		    oskit_entropy_getstats(entropy_aref[i], &stats);
+		    n_calls = stats.n_calls;
+		    entropy_count = stats.entropy_count;
+		    osenv_log(OSENV_LOG_INFO,
+			      "DLD: stats n_calls is %d entropy_count is %d\n",
+			      n_calls, entropy_count);
+
+		    oskit_stream_release(stream);
+		    oskit_asyncio_release(asyncio);
+		}
+	    }
+	}
+    }
+    
+    oskit_dump_drivers();
+    
+    return rc;
+}
+
+
+/* End of rndunittest.c */
diff -ruN oskit-20020317/linux/dev/GNUmakerules oskit-20020317-entropy/linux/dev/GNUmakerules
--- oskit-20020317/linux/dev/GNUmakerules	Wed Jan 30 19:40:57 2002
+++ oskit-20020317-entropy/linux/dev/GNUmakerules	Thu Jan  2 11:04:43 2003
@@ -22,7 +22,8 @@
 SRCDIRS +=	$(OSKIT_SRCDIR)/linux/dev			\
 		$(OSKIT_SRCDIR)/linux/src/drivers/block		\
 		$(OSKIT_SRCDIR)/linux/src/drivers/pci		\
-		$(OSKIT_SRCDIR)/linux/src/drivers/sound
+		$(OSKIT_SRCDIR)/linux/src/drivers/sound		\
+		$(OSKIT_SRCDIR)/linux/src/drivers/char
 
 ifeq ($(HOST_ARCH),arm32)
 # XXX hack for dma code
@@ -47,9 +48,10 @@
 # to ensure linker namespace cleanliness and avoid conflicts.
 OSKIT_CPPFLAGS += -include $(OSKIT_SRCDIR)/linux/dev/global.h
 
-# Define SCSIDRIVERS and ETHERDRIVERS.
+# Define SCSIDRIVERS, ETHERDRIVERS and ENTROPYDRIVERS.
 -include scsidrivers
 -include etherdrivers
+-include entropydrivers
 
 # Build individual glue files for the SCSI and Ethernet drivers; see below.
 SCSIGLUE_CFILES := $(addsuffix _scsiglue.c,$(SCSIDRIVERS))
@@ -58,9 +60,13 @@
 ETHERGLUE_CFILES := $(addsuffix _etherglue.c,$(ETHERDRIVERS))
 OBJFILES += $(addsuffix _etherglue.o,$(ETHERDRIVERS))
 CLEAN_FILES += etherdrivers $(addsuffix _etherglue.c,$(ETHERDRIVERS))
+ENTROPYGLUE_CFILES := $(addsuffix _entropyglue.c,$(ENTROPYDRIVERS))
+OBJFILES += $(addsuffix _entropyglue.o,$(ENTROPYDRIVERS))
+CLEAN_FILES += entropydrivers $(addsuffix _entropyglue.c,$(ENTROPYDRIVERS))
 
 .PRECIOUS: $(SCSIGLUE_CFILES)
 .PRECIOUS: $(ETHERGLUE_CFILES)
+.PRECIOUS: $(ENTROPYGLUE_CFILES)
 
 # Figure out which driver and shared files to actually compile.
 # This mostly depends on the contents of $(ETHERDRIVERS), etc; see below.
@@ -74,6 +80,8 @@
 ifneq ($(HOST_ARCH),arm32)
 OBJFILES += $(SCSIOBJS)
 endif
+ENTROPYOBJS := random.o
+OBJFILES += $(ENTROPYOBJS)
 
 ## The aha152x driver requires a compile-time define.
 ## We just use AUTOCONF.  Look at the driver for more info.
@@ -180,12 +188,29 @@
 	echo '#include "ethernet.h"' >$@
 	grep 'driver.*"$(patsubst %_etherglue.c,%,$@)",' $< >>$@
 
+#
+#
+GNUmakefile: entropydrivers
+entropydrivers: $(OSKIT_SRCDIR)/oskit/dev/linux_entropy.h
+	$(OSKIT_QUIET_MAKE_INFORM) "Generating makefile fragment $@"
+	(echo "#define entropy(n,d,v,a,f,p) f"; echo "#include \"$<\"") \
+	| $(CC) -E - $(DEFINES) \
+	| sed '/^#/d;s/"//g' \
+	| awk 'BEGIN { printf "ENTROPYDRIVERS ="; } { printf " %s", $$1; }' >$@
+
+%_entropyglue.c: $(OSKIT_SRCDIR)/oskit/dev/linux_entropy.h
+	$(OSKIT_QUIET_MAKE_INFORM) "Generating $@"
+	echo '#include "entropy.h"' >$@
+	grep 'entropy.*"$(patsubst %_entropyglue.c,%,$@)",' $< >>$@
+
 # When using Knit, we generate all the stub files up-front by
 # making these targets.  (This is ok because the files are tiny.)
 scsi_gluefiles:  $(addsuffix _scsiglue.c, $(SCSIDRIVERS))
 ether_gluefiles: $(addsuffix _etherglue.c,$(ETHERDRIVERS))
+entropy_gluefiles: $(addsuffix _entropyglue.c,$(ENTROPYDRIVERS))
 
 prepare:: scsi_gluefiles
 prepare:: ether_gluefiles
+prepare:: entropy_gluefiles
 
 endif
diff -ruN oskit-20020317/linux/dev/entropy.c oskit-20020317-entropy/linux/dev/entropy.c
--- oskit-20020317/linux/dev/entropy.c	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/linux/dev/entropy.c	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,877 @@
+#include <oskit/c/assert.h>
+#include <oskit/dev/error.h>
+#include <oskit/dev/linux.h>
+#include <oskit/com/stream.h>
+#include <oskit/com/listener.h>
+#include <oskit/com/listener_mgr.h>
+#include <oskit/io/asyncio.h>
+#include <oskit/dev/entropy.h>
+#include <oskit/dev/entropy_channel.h>
+#include "glue.h"
+#include "entropy.h"
+#include "entropy_driver.h"
+#include "entropy_impl.h"
+#include <linux/malloc.h>
+
+/*
+  Copyright (c) 2002, 2003 Derek L Davies (ddavies@ddavies.net)
+*/
+
+/*#if LINUX_RANDOM_DEVICE*/
+#include <linux/random.h>
+int random_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+extern ssize_t random_read(struct file *, char *, size_t, loff_t *);
+extern ssize_t random_read_unlimited(struct file *, char *, size_t, loff_t *);
+extern ssize_t random_write(struct file *, const char *, size_t, loff_t *);
+/*#endif*/
+
+struct device *dev_base;
+
+struct oskit_guid oskit_linux_entropy_iids[ENTROPY_NIIDS] = {
+    OSKIT_DEVICE_IID,
+    OSKIT_DRIVER_IID,
+    OSKIT_ENTROPY_IID
+};
+
+typedef struct entropy_noblock_stream_impl {
+    oskit_stream_t is;
+    unsigned int count;
+    entropy_impl_t *ei;
+    oskit_osenv_mem_t *mem;
+} entropy_noblock_stream_impl_t;
+
+typedef struct entropy_good_stream_impl {
+    oskit_stream_t is;
+    unsigned int count;
+    entropy_impl_t *ei;
+    oskit_osenv_mem_t *mem;
+} entropy_good_stream_impl_t;
+
+typedef struct entropy_good_asyncio_impl {
+    oskit_asyncio_t ia;
+    unsigned int count;
+    entropy_impl_t *ei;
+    oskit_osenv_mem_t *mem;
+    oskit_u32_t selmask;
+    struct listener_mgr *readers;
+} entropy_good_asyncio_impl_t;
+
+static struct oskit_stream_ops noblockstreamops;
+static struct oskit_stream_ops goodstreamops;
+static struct oskit_asyncio_ops goodasyncioops;
+
+static OSKIT_COMDECL
+entropy_query(oskit_entropy_t *e, const oskit_iid_t *iid, void **out_ihandle)
+{
+    if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 ||
+	memcmp(iid, &oskit_driver_iid, sizeof(*iid)) == 0 ||
+	memcmp(iid, &oskit_device_iid, sizeof(*iid)) == 0 ||
+	memcmp(iid, &oskit_entropy_iid, sizeof(*iid)) == 0) {
+	*out_ihandle = e;
+	oskit_entropy_addref(e);
+	return 0;
+    }
+
+    *out_ihandle = 0;
+    return OSKIT_E_NOINTERFACE;
+};
+
+static OSKIT_COMDECL_U
+entropy_addref(oskit_entropy_t *e)
+{
+    entropy_impl_t *ei = (entropy_impl_t *)e;
+    return ++(ei->count);
+}
+
+static OSKIT_COMDECL_U
+entropy_release(oskit_entropy_t *e)
+{
+    entropy_impl_t *ei = (entropy_impl_t *)e;
+    
+    /* We never actually free the entropy pool(s),
+       it exists for the life of the kernel.
+       Memory is allocated in the entropy probe
+       function, below.
+    */
+    if (ei->count > 0) {
+	(ei->count)--;
+    }
+    return ei->count;
+}
+
+static OSKIT_COMDECL
+entropy_getinfo(oskit_entropy_t *e, oskit_devinfo_t *out_info)
+{
+    entropy_impl_t* ei = (entropy_impl_t*)e;
+    *out_info = ei->ds->info;
+    return 0;
+}
+
+static OSKIT_COMDECL
+entropy_getdriver(oskit_entropy_t *e, oskit_driver_t **out_driver)
+{
+    entropy_impl_t* ei = (entropy_impl_t*)e;
+    *out_driver = (oskit_driver_t*)&(ei->ds->drvi);
+    oskit_driver_addref(*out_driver);
+    return 0;
+}
+
+static OSKIT_COMDECL
+entropy_getstats(oskit_entropy_t *e, oskit_entropy_stats_t *out_stats)
+{
+    entropy_impl_t* ei = (entropy_impl_t*)e;
+
+    /* Update getstats call count.
+    */
+    (ei->stats.n_calls)++;
+    out_stats->n_calls = ei->stats.n_calls;
+
+/*#ifdef LINUX_RANDOM_POOL*/
+    {
+	/* Obtain estimated entropy.  The first arg, a struct inode *,
+	   is never actually used in the ioctl routine.
+	*/
+	random_ioctl(NULL, &(ei->fs), RNDGETENTCNT,
+		     (unsigned long)(&(ei->stats.entropy_count)));
+    }
+/*#endif*/
+
+    out_stats->entropy_count = ei->stats.entropy_count;
+    
+    return 0;
+}
+
+static OSKIT_COMDECL
+entropy_attach_source(oskit_entropy_t *e, char *name,
+		      oskit_u32_t type, oskit_u32_t flags,
+		      oskit_entropy_channel_t **out_chan)
+{
+    entropy_impl_t *ei = (entropy_impl_t *)e;
+    oskit_entropy_channel_t *c;
+    oskit_error_t err;
+
+    err = create_entropy_channel(ei->mem, e, &c);
+    if (err) return err;
+
+    *out_chan = c;
+    return 0;
+}
+
+static OSKIT_COMDECL
+entropy_open_nonblocking(oskit_entropy_t *e, oskit_stream_t **out_stream_obj)
+{
+    entropy_impl_t *ei = (entropy_impl_t *)e;
+    entropy_noblock_stream_impl_t *si;
+    
+    osenv_log(OSENV_LOG_DEBUG, "DLD: open_good ei is %p\n", ei);
+
+    si = (entropy_noblock_stream_impl_t *)oskit_osenv_mem_alloc(ei->mem,
+								sizeof(*si),
+								0, 0);
+    if (si == NULL)
+	return NULL;
+    memset(si, 0, sizeof(*si));
+
+    osenv_log(OSENV_LOG_DEBUG, "DLD: open_good si is %p\n", si);
+
+    si->count = 1;
+    si->is.ops = &noblockstreamops;
+
+    /* FIXME: Do I need to refcount mem too? */
+    si->mem = ei->mem;
+
+    /* FIXME: Do I need to refcount ei too? */
+    si->ei = ei;
+    
+    *out_stream_obj = (oskit_stream_t *)si;
+
+    return 0;
+}
+
+static OSKIT_COMDECL
+entropy_open_good(oskit_entropy_t *e, oskit_stream_t **out_stream_obj,
+		  oskit_asyncio_t **out_asyncio_obj)
+{
+    entropy_impl_t *ei = (entropy_impl_t *)e;
+    entropy_good_stream_impl_t *si;
+    entropy_good_asyncio_impl_t *ai;
+
+    osenv_log(OSENV_LOG_DEBUG, "DLD: open_good ei is %p\n", ei);
+    
+    si = (entropy_good_stream_impl_t *)oskit_osenv_mem_alloc(ei->mem,
+							     sizeof(*si),
+							     0, 0);
+    if (si == NULL)
+	return NULL;
+    memset(si, 0, sizeof(*si));
+
+    osenv_log(OSENV_LOG_DEBUG, "DLD: open_good si is %p\n", si);
+
+    si->count = 1;
+    si->is.ops = &goodstreamops;
+
+    /* FIXME: Do I need to refcount mem too? */
+    si->mem = ei->mem;
+
+    /* FIXME: Do I need to refcount ei too? */
+    si->ei = ei;
+
+    *out_stream_obj = (oskit_stream_t *)si;
+
+    ai = (entropy_good_asyncio_impl_t *)oskit_osenv_mem_alloc(ei->mem,
+							      sizeof(*ai),
+							      0, 0);
+    if (ai == NULL)
+    {
+	oskit_osenv_mem_t *mem = si->mem;
+	oskit_osenv_mem_free(mem, (void*)si, 0, sizeof(*si));
+	return NULL;
+    }
+    memset(ai, 0, sizeof(*ai));
+
+    osenv_log(OSENV_LOG_DEBUG, "DLD: open_good ai is %p\n", ai);
+    
+    ai->count = 1;
+    ai->ia.ops = &goodasyncioops;
+
+    /* Always writable. */
+    ai->selmask = OSKIT_ASYNCIO_WRITABLE;
+
+    /* FIXME: Do I need to refcount mem too? */
+    ai->mem = ei->mem;
+
+    /* FIXME: Do I need to refcount ei too? */
+    ai->ei = ei;
+
+    *out_asyncio_obj = (oskit_asyncio_t *)ai;
+
+    return 0;
+}
+
+struct oskit_entropy_ops
+oskit_linux_entropy_ops = {
+    entropy_query, entropy_addref, entropy_release,
+    entropy_getinfo, entropy_getdriver, entropy_getstats,
+    entropy_attach_source, entropy_open_nonblocking,
+    entropy_open_good
+};
+
+static OSKIT_COMDECL_U
+entropy_noblock_stream_addref(oskit_stream_t *);
+
+static OSKIT_COMDECL
+entropy_noblock_stream_query(oskit_stream_t *s, const oskit_iid_t *iid,
+			     void **out_ihandle)
+{
+    if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 ||
+	memcmp(iid, &oskit_stream_iid, sizeof(*iid)) == 0) {
+	*out_ihandle = s;
+	entropy_noblock_stream_addref(s);
+	return 0;
+    }
+
+    *out_ihandle = 0;
+    return OSKIT_E_NOINTERFACE;
+}
+
+static OSKIT_COMDECL_U
+entropy_noblock_stream_addref(oskit_stream_t *s)
+{
+    entropy_noblock_stream_impl_t *si = (entropy_noblock_stream_impl_t *)s;
+    return ++si->count;
+}
+
+static OSKIT_COMDECL_U
+entropy_noblock_stream_release(oskit_stream_t *s)
+{
+    entropy_noblock_stream_impl_t *si = (entropy_noblock_stream_impl_t *)s;
+    unsigned int newcount;
+
+    if (si == NULL)
+	osenv_panic("%s:%d: null entropy_noblock_stream_impl_t",
+		    __FILE__, __LINE__);
+    if (si->count == 0)
+	osenv_panic("%s:%d: bad count", __FILE__, __LINE__);
+
+    if ((newcount = --si->count) == 0) {
+	oskit_osenv_mem_t *mem = si->mem;
+	oskit_osenv_mem_free(mem, (void*)si, 0, sizeof(*si));
+    }
+    
+    return newcount;
+}
+
+static OSKIT_COMDECL
+entropy_noblock_stream_read(oskit_stream_t *s, void* buf, oskit_u32_t len,
+			    oskit_u32_t *out_actual)
+{
+    entropy_noblock_stream_impl_t *si = (entropy_noblock_stream_impl_t *)s;
+    entropy_impl_t *ei = si->ei;
+    
+/*#ifdef LINUX_RANDOM_POOL*/
+    /* The fourth argument to random_read_unlimited, ppos, a 'loff_t *', is
+       unused in the linux 2.2.12 implementation.
+    */
+    *out_actual = (oskit_u32_t)random_read_unlimited(&(ei->fs), (char *)buf,
+						     (size_t)len, NULL);
+/*#endif*/
+
+    return 0;
+}
+
+static OSKIT_COMDECL
+entropy_noblock_stream_write(oskit_stream_t *s, const void *buf,
+			     oskit_u32_t len, oskit_u32_t * out_actual)
+{
+    entropy_noblock_stream_impl_t *si = (entropy_noblock_stream_impl_t *)s;
+    entropy_impl_t *ei = si->ei;
+    int err;
+
+/*#ifdef LINUX_RANDOM_POOL*/
+    /* The fourth argument to random_write, ppos, a 'loff_t *', is unused in
+       the linux 2.2.12 implementation.
+    */
+    *out_actual = (oskit_u32_t)random_write(&(ei->fs), (const char *)buf,
+					    (size_t)len, NULL);
+
+    /* Up the entropy bit count.  The linux random device does not do this
+       for us.
+
+       FIXME: We give it one bit of entropy for each byte (which is totally
+       bogus, of course).
+    */
+    err = random_ioctl(NULL, &(ei->fs), RNDADDTOENTCNT, (int *)out_actual);
+
+/*#endif*/
+    return 0;
+}
+
+static OSKIT_COMDECL
+entropy_noblock_stream_seek(oskit_stream_t *s, oskit_s64_t ofs,
+			    oskit_seek_t whence, oskit_u64_t * out_newpos)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_noblock_stream_setsize(oskit_stream_t *s, oskit_u64_t new_size)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_noblock_stream_copyto(oskit_stream_t *s, oskit_stream_t *dst,
+			      oskit_u64_t size, oskit_u64_t *out_read,
+			      oskit_u64_t *out_written)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_noblock_stream_commit(oskit_stream_t *s, oskit_u32_t commit_flags)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_noblock_stream_revert(oskit_stream_t *s)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_noblock_stream_lockregion(oskit_stream_t *s, oskit_u64_t offset,
+				  oskit_u64_t size, oskit_u32_t lock_type)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_noblock_stream_unlockregion(oskit_stream_t *s, oskit_u64_t offset,
+				    oskit_u64_t size, oskit_u32_t lock_type)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_noblock_stream_stat(oskit_stream_t *s, oskit_stream_stat_t *out_stat,
+			    oskit_u32_t stat_flags)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_noblock_stream_clone(oskit_stream_t *s, oskit_stream_t **out_stream)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static struct oskit_stream_ops noblockstreamops =
+{
+    entropy_noblock_stream_query,
+    entropy_noblock_stream_addref,
+    entropy_noblock_stream_release,
+    entropy_noblock_stream_read,
+    entropy_noblock_stream_write,
+    entropy_noblock_stream_seek,
+    entropy_noblock_stream_setsize,
+    entropy_noblock_stream_copyto,
+    entropy_noblock_stream_commit,
+    entropy_noblock_stream_revert,
+    entropy_noblock_stream_lockregion,
+    entropy_noblock_stream_unlockregion,
+    entropy_noblock_stream_stat,
+    entropy_noblock_stream_clone
+};
+
+static OSKIT_COMDECL_U
+entropy_good_stream_addref(oskit_stream_t *);
+
+static OSKIT_COMDECL
+entropy_good_stream_query(oskit_stream_t *s, const oskit_iid_t *iid,
+			  void **out_ihandle)
+{
+    if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 ||
+	memcmp(iid, &oskit_stream_iid, sizeof(*iid)) == 0) {
+	*out_ihandle = s;
+	entropy_good_stream_addref(s);
+	return 0;
+    }
+
+    *out_ihandle = 0;
+    return OSKIT_E_NOINTERFACE;
+}
+
+static OSKIT_COMDECL_U
+entropy_good_stream_addref(oskit_stream_t *s)
+{
+    entropy_good_stream_impl_t *si = (entropy_good_stream_impl_t *)s;
+    return ++si->count;
+}
+
+static OSKIT_COMDECL_U
+entropy_good_stream_release(oskit_stream_t *s)
+{
+    entropy_good_stream_impl_t *si = (entropy_good_stream_impl_t *)s;
+    unsigned int newcount;
+
+    if (si == NULL)
+	osenv_panic("%s:%d: null entropy_good_stream_impl_t",
+		    __FILE__, __LINE__);
+    if (si->count == 0)
+	osenv_panic("%s:%d: bad count",
+		    __FILE__, __LINE__);
+
+    if ((newcount = --si->count) == 0) {
+	oskit_osenv_mem_t *mem = si->mem;
+	oskit_osenv_mem_free(mem, (void*)si, 0, sizeof(*si));
+    }
+    
+    return newcount;
+}
+
+static OSKIT_COMDECL
+entropy_good_stream_read(oskit_stream_t *s, void* buf, oskit_u32_t len,
+			 oskit_u32_t *out_actual)
+{
+    entropy_good_stream_impl_t *si = (entropy_good_stream_impl_t *)s;
+    entropy_impl_t *ei = si->ei;
+
+/*#ifdef LINUX_RANDOM_POOL*/
+    /* The fourth argument to random_read, ppos, a 'loff_t *', is unused in the
+       linux 2.2.12 implementation.
+    */
+    *out_actual = (oskit_u32_t)random_read(&(ei->fs), (char *)buf,
+					   (size_t)len, NULL);
+/*#endif*/
+
+    return 0;
+}
+
+static OSKIT_COMDECL
+entropy_good_stream_write(oskit_stream_t *s, const void *buf, oskit_u32_t len,
+			  oskit_u32_t * out_actual)
+{
+    entropy_good_stream_impl_t *si = (entropy_good_stream_impl_t *)s;
+    entropy_impl_t *ei = si->ei;
+    int err;
+
+/*#ifdef LINUX_RANDOM_POOL*/
+    /* The fourth argument to random_write, ppos, a 'loff_t *', is unused in
+       the linux 2.2.12 implementation.
+    */
+    *out_actual = (oskit_u32_t)random_write(&(ei->fs), (char *)buf,
+					    (size_t)len, NULL);
+
+    /* Up the entropy bit count.  The linux random device does not do this
+       for us.
+
+       FIXME: We give it one bit of entropy for each byte (which is totally
+       bogus, of course).
+    */
+    err = random_ioctl(NULL, &(ei->fs), RNDADDTOENTCNT, (int *)out_actual);
+/*#endif*/
+
+    return 0;
+}
+
+static OSKIT_COMDECL
+entropy_good_stream_seek(oskit_stream_t *s, oskit_s64_t ofs,
+			 oskit_seek_t whence, oskit_u64_t * out_newpos)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_good_stream_setsize(oskit_stream_t *s, oskit_u64_t new_size)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_good_stream_copyto(oskit_stream_t *s, oskit_stream_t *dst,
+			   oskit_u64_t size, oskit_u64_t *out_read,
+			   oskit_u64_t *out_written)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_good_stream_commit(oskit_stream_t *s, oskit_u32_t commit_flags)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_good_stream_revert(oskit_stream_t *s)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_good_stream_lockregion(oskit_stream_t *s, oskit_u64_t offset,
+			       oskit_u64_t size, oskit_u32_t lock_type)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_good_stream_unlockregion(oskit_stream_t *s, oskit_u64_t offset,
+				 oskit_u64_t size, oskit_u32_t lock_type)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_good_stream_stat(oskit_stream_t *s, oskit_stream_stat_t *out_stat,
+			 oskit_u32_t stat_flags)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static OSKIT_COMDECL
+entropy_good_stream_clone(oskit_stream_t *s, oskit_stream_t **out_stream)
+{
+    return OSKIT_E_NOTIMPL;
+}
+
+static struct oskit_stream_ops goodstreamops =
+{
+    entropy_good_stream_query,
+    entropy_good_stream_addref,
+    entropy_good_stream_release,
+    entropy_good_stream_read,
+    entropy_good_stream_write,
+    entropy_good_stream_seek,
+    entropy_good_stream_setsize,
+    entropy_good_stream_copyto,
+    entropy_good_stream_commit,
+    entropy_good_stream_revert,
+    entropy_good_stream_lockregion,
+    entropy_good_stream_unlockregion,
+    entropy_good_stream_stat,
+    entropy_good_stream_clone
+};
+
+static OSKIT_COMDECL_U
+entropy_good_asyncio_addref(oskit_asyncio_t *);
+
+static OSKIT_COMDECL
+entropy_good_asyncio_query(oskit_asyncio_t *a, const oskit_iid_t *iid,
+			   void **out_ihandle)
+{
+    if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 ||
+	memcmp(iid, &oskit_asyncio_iid, sizeof(*iid)) == 0) {
+	*out_ihandle = a;
+	entropy_good_asyncio_addref(a);
+	return 0;
+    }
+
+    *out_ihandle = 0;
+    return OSKIT_E_NOINTERFACE;
+}
+
+static OSKIT_COMDECL_U
+entropy_good_asyncio_addref(oskit_asyncio_t *a)
+{
+    entropy_good_asyncio_impl_t *ai = (entropy_good_asyncio_impl_t *)a;
+    return ++ai->count;
+}
+
+static OSKIT_COMDECL_U
+entropy_good_asyncio_release(oskit_asyncio_t *a)
+{
+    entropy_good_asyncio_impl_t *ai = (entropy_good_asyncio_impl_t *)a;
+    unsigned int newcount;
+
+    if (ai == NULL)
+	osenv_panic("%s:%d: null entropy_good_asyncio_impl_t",
+		    __FILE__, __LINE__);
+    if (ai->count == 0)
+	osenv_panic("%s:%d: bad count", __FILE__, __LINE__);
+
+    if ((newcount = --ai->count) == 0) {
+	oskit_osenv_mem_t *mem = ai->mem;
+	oskit_osenv_mem_free(mem, (void*)ai, 0, sizeof(*ai));
+    }
+    
+    return newcount;
+}
+
+static int
+entropy_is_readable(oskit_entropy_t *e)
+{
+    oskit_entropy_stats_t stats;
+    oskit_entropy_getstats(e, &stats);
+    return stats.entropy_count > 0;
+}
+
+static OSKIT_COMDECL
+entropy_good_asyncio_poll(oskit_asyncio_t *a)
+{
+    entropy_good_asyncio_impl_t *ai = (entropy_good_asyncio_impl_t *)a;
+    oskit_entropy_t *e = (oskit_entropy_t *)ai->ei;
+    oskit_error_t mask = OSKIT_ASYNCIO_WRITABLE;
+    int enabled;
+
+    enabled = osenv_intr_save_disable();
+    
+    if (entropy_is_readable(e))
+	mask |= OSKIT_ASYNCIO_READABLE;
+    
+    if (enabled)
+	osenv_intr_enable();
+    
+    return mask;
+}
+
+static OSKIT_COMDECL
+entropy_good_asyncio_add_listener(oskit_asyncio_t *a, struct oskit_listener *l,
+				  oskit_s32_t mask)
+{
+    entropy_good_asyncio_impl_t *ai = (entropy_good_asyncio_impl_t *)a;
+    oskit_error_t retmask = OSKIT_ASYNCIO_WRITABLE;
+    int enabled;
+#if 0 /* UNIX */
+    unsigned int iotype = 0;
+#endif
+
+    enabled = osenv_intr_save_disable();
+
+    retmask = entropy_good_asyncio_poll(a);
+
+    oskit_listener_mgr_add(ai->readers, l);    
+
+#if 0 /* UNIX */
+    if (mask & OSKIT_ASYNCIO_READABLE) {
+	iotype |= IOTYPE_READ;
+    }
+    if (mask & OSKIT_ASYNCIO_WRITABLE) {
+	iotype |= IOTYPE_WRITE;
+    }
+#endif
+
+    ai->selmask |= mask;
+#if 0 /* UNIX */
+    oskitunix_register_async_fd(ei->fd, iotype, asyncio_callback, ai);
+#endif
+    
+    if (enabled)
+	osenv_intr_enable();
+    return retmask;
+}
+
+static OSKIT_COMDECL
+entropy_good_asyncio_remove_listener(oskit_asyncio_t *a,
+				     struct oskit_listener *l0)
+{
+    entropy_good_asyncio_impl_t *ai = (entropy_good_asyncio_impl_t *)a;
+    int enabled;
+    oskit_error_t rc;
+
+    enabled = osenv_intr_save_disable();
+
+    rc = oskit_listener_mgr_remove(ai->readers, l0);
+    if (oskit_listener_mgr_count(ai->readers) == 0)
+	ai->selmask &= ~OSKIT_ASYNCIO_READABLE;
+
+#if 0 /* UNIX */
+    if (! ai->selmask)
+	oskitunix_unregister_async_fd(ai->fd);
+#endif
+
+    if (enabled)
+	osenv_intr_enable();
+
+    return 0;
+}
+
+static OSKIT_COMDECL
+entropy_good_asyncio_readable(oskit_asyncio_t *a)
+{
+    entropy_good_asyncio_impl_t *ai = (entropy_good_asyncio_impl_t *)a;
+    oskit_entropy_t *e = (oskit_entropy_t *)ai->ei;
+    oskit_entropy_stats_t stats;
+
+    oskit_entropy_getstats(e, &stats);
+
+#if 0 /* UNIX */
+    rc = NATIVEOS(ioctl)(si->fd, FIONREAD, &b);
+#endif
+    
+    /* The idea is to return the number of full
+       good entropy bytes that can be read.
+    */
+    return stats.entropy_count / 8;
+}
+
+static struct oskit_asyncio_ops goodasyncioops =
+{
+    entropy_good_asyncio_query,
+    entropy_good_asyncio_addref,
+    entropy_good_asyncio_release,
+    entropy_good_asyncio_poll,
+    entropy_good_asyncio_add_listener,
+    entropy_good_asyncio_remove_listener,
+    entropy_good_asyncio_readable,
+};
+
+void
+oskit_linux_entropy_add_data(oskit_entropy_t *e, void *data, oskit_u32_t len,
+			     oskit_u32_t entropy)
+{
+    entropy_impl_t *ei = (entropy_impl_t *)e;
+    
+/*#ifdef LINUX_RANDOM_POOL*/
+    {
+	oskit_u32_t buf[3];
+	/* The first arg, a struct inode *, is never actually used.
+	 */
+	buf[0] = entropy;
+	buf[1] = len;
+	buf[2] = (int *)data; /* FIXME: Sketchy... */
+	random_ioctl(NULL, &(ei->fs), RNDADDENTROPY, (int*)buf);
+    }
+/*#endif*/
+}
+
+oskit_error_t
+oskit_linux_entropy_probe(struct driver_struct *ds)
+{
+    struct entropy_driver *drv = (struct entropy_driver*)ds;
+    struct device *ldev;
+    int found = 0;
+    struct device **dp;
+    int devnum;
+
+    /*
+      The general idea here was snarfed from net.c's
+      oskit_linux_netdev_probe_raw()
+    */
+    
+    osenv_process_lock();
+
+    oskit_linux_init_entropy();
+
+    osenv_log(OSENV_LOG_DEBUG, "Probing %s\n", ds->info.name);
+
+    /* The magic "8" is appently the maximum size of the
+       string pointed to by name.  FIXME: check this out
+       and equate the magic number with some meaningful
+       symbol.
+    */
+    ldev = kmalloc(sizeof(*ldev) + 8, GFP_KERNEL);
+    if (ldev == NULL)
+    {
+	return OSKIT_E_OUTOFMEMORY;
+    }
+    osenv_log(OSENV_LOG_DEBUG, "DLD: Created ldev at %p\n", ldev);
+    memset(ldev, 0, sizeof(*ldev));
+    ldev->name = (char*)(ldev + 1);
+    devnum = 0;
+    retry:
+    /* We only have 8 bytes for this name (base + unit num)
+    */
+    osenv_log(OSENV_LOG_DEBUG, "DLD: basename is %s\n", drv->basename);
+    /*FIXME assert(strlen(drv->basename) < (8 - 1));*/
+    assert(devnum < 10);
+    sprintf(ldev->name, "%s%d", drv->basename, devnum);
+    for (dp = &dev_base; *dp; dp = &(*dp)->next)
+	if (strcmp(ldev->name, (*dp)->name) == 0) {
+	    devnum++;
+	    goto retry;
+	}
+    *dp = ldev;
+
+    drv->probe(ldev);
+
+    for (ldev = dev_base; ldev; ldev = ldev->next) {
+	oskit_osenv_t *osenv;
+	oskit_osenv_mem_t *mem;
+	entropy_impl_t *entropy;
+
+	if (ldev->my_alias != NULL)
+	    continue;
+
+	assert(ldev->name != NULL);
+
+	entropy = kmalloc(sizeof(*entropy), GFP_KERNEL);
+	if (entropy == NULL)
+	{
+	    return OSKIT_E_OUTOFMEMORY;
+	}
+	osenv_log(OSENV_LOG_DEBUG,
+		  "DLD: Created entropy pool at %p\n", entropy);
+	memset(entropy, 0, sizeof(*entropy));
+	entropy->ie.ops = &oskit_linux_entropy_ops;
+	entropy->count = 1;
+	ldev->my_alias = entropy;
+	entropy->ds = ds;
+	entropy->fs.f_dentry = &(entropy->des);
+	entropy->des.d_inode = &(entropy->in);
+	entropy->stats.n_calls = 0;
+	entropy->stats.entropy_count = 0;
+	
+	/* Now we need a way to get memory for entropy channels.
+	*/
+	oskit_lookup_first(&oskit_osenv_iid, (void *) &osenv);
+	if (!osenv) panic("DLD: osenv not yet registered.");
+	oskit_osenv_lookup(osenv, &oskit_osenv_mem_iid, (void *)&mem);
+	oskit_osenv_release(osenv);
+	entropy->mem = mem;
+
+	/* And register the entropy pool device.
+	*/
+	osenv_device_register((oskit_device_t*)entropy,
+			      drv->dev_iids,
+			      drv->dev_niids);
+
+	found++;
+    }
+
+    osenv_process_unlock();
+    
+    return found;
+}
+
+/* End of entropy.c */
diff -ruN oskit-20020317/linux/dev/entropy.h oskit-20020317-entropy/linux/dev/entropy.h
--- oskit-20020317/linux/dev/entropy.h	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/linux/dev/entropy.h	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,32 @@
+
+#ifndef _LINUX_DEV_ENTROPY_H_
+#define _LINUX_DEV_ENTROPY_H_
+
+#include <linux/version.h>
+#include "glue.h"
+#include "entropy_driver.h"
+
+extern struct oskit_entropy_ops oskit_linux_entropy_ops;
+
+/* oskit_unknown, oskit_device_t, oskit_driver_t */
+#define ENTROPY_NIIDS 3
+extern struct oskit_guid oskit_linux_entropy_iids[ENTROPY_NIIDS];
+
+#define entropy(name, description, vendor, author, filename, probe) \
+        extern void rand_initialize(void); \
+        static struct entropy_driver fdev_drv = { \
+                { { &oskit_linux_driver_ops }, \
+                  oskit_linux_entropy_probe, \
+		  { #name, description " Entropy driver", vendor, \
+		    author, "Linux "UTS_RELEASE } }, \
+                { #name, description " Entropy device", vendor, \
+                  author, "Linux "UTS_RELEASE }, \
+                (struct oskit_entropy_driver_ops*)&oskit_linux_entropy_ops, \
+                "entropy", \
+                oskit_linux_entropy_iids, ENTROPY_NIIDS, \
+                rand_initialize }; \
+        oskit_error_t oskit_linux_init_entropy_##name(void) { \
+                return oskit_linux_driver_register(&fdev_drv.ds); \
+        }
+
+#endif /*  _LINUX_DEV_ENTROPY_H_ */
diff -ruN oskit-20020317/linux/dev/entropy_channel.c oskit-20020317-entropy/linux/dev/entropy_channel.c
--- oskit-20020317/linux/dev/entropy_channel.c	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/linux/dev/entropy_channel.c	Thu Jan  2 11:40:36 2003
@@ -0,0 +1,111 @@
+#include <oskit/dev/entropy_channel.h>
+#include <oskit/dev/entropy.h>
+#include "entropy_impl.h"
+
+/*
+  This code copyright (c) 2002, 2003 Derek L Davies (ddavies@ddavies.net)
+*/
+
+void oskit_linux_entropy_add_data(oskit_entropy_t *, void *,
+				  oskit_u32_t, oskit_u32_t);
+
+typedef struct entropy_channel_impl {
+	oskit_entropy_channel_t iec;
+	oskit_entropy_t *ep;
+	unsigned count;
+} entropy_channel_impl_t;
+
+static OSKIT_COMDECL
+entropy_channel_query(oskit_entropy_channel_t *e,
+		      const oskit_iid_t *iid,
+		      void **out_ihandle)
+{
+    entropy_channel_impl_t *ei = (entropy_channel_impl_t *)e;
+
+    osenv_assert(ei != NULL);
+    osenv_assert(ei->count != 0);
+	
+    if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 ||
+	memcmp(iid, &oskit_entropy_channel_iid, sizeof(*iid)) == 0) {
+	*out_ihandle = e;
+	++ei->count;
+	return 0;
+    }
+
+    *out_ihandle = NULL;
+    return OSKIT_E_NOINTERFACE;
+}
+
+static OSKIT_COMDECL_U
+entropy_channel_addref(oskit_entropy_channel_t *e)
+{
+    entropy_channel_impl_t *ei = (entropy_channel_impl_t *)e;
+
+    osenv_assert(ei != NULL);
+    osenv_assert(ei->count != 0);
+
+    return ++(ei->count);
+}
+
+static OSKIT_COMDECL_U
+entropy_channel_release(oskit_entropy_channel_t *e)
+{
+	entropy_channel_impl_t *ei = (entropy_channel_impl_t *)e;
+	unsigned newcount;
+
+	osenv_assert(ei != NULL);
+	osenv_assert(ei->count != 0);
+
+	newcount = --ei->count;
+	if (newcount == 0) {
+	    oskit_osenv_mem_t *mem = ((entropy_impl_t*)ei->ep)->mem;
+	    oskit_osenv_mem_free(mem, (void*)ei, 0, sizeof(*ei));
+	}
+	return newcount;
+}
+
+static OSKIT_COMDECL_V
+entropy_channel_add_data(oskit_entropy_channel_t *ec, void *data,
+			 oskit_u32_t len, oskit_u32_t entropy)
+{
+    entropy_channel_impl_t *eci = (entropy_channel_impl_t *)ec;
+    entropy_impl_t *ei = (entropy_impl_t *)(eci->ep);
+    oskit_linux_entropy_add_data((oskit_entropy_t *)ei, data, len, entropy);
+    return;
+}
+
+static OSKIT_COMDECL_V
+entropy_channel_get_stats(oskit_entropy_channel_t *e,
+			  oskit_entropy_stats_t *stats)
+{
+    entropy_channel_impl_t *ei = (entropy_channel_impl_t *)e;
+    oskit_entropy_getstats(ei->ep, stats);
+    return;
+}
+
+static struct oskit_entropy_channel_ops entropy_channel_ops = {
+    entropy_channel_query, entropy_channel_addref, entropy_channel_release,
+    entropy_channel_add_data, entropy_channel_get_stats
+};
+
+oskit_error_t create_entropy_channel(oskit_osenv_mem_t *mem,
+				     oskit_entropy_t *ep,
+				     oskit_entropy_channel_t **out_chan)
+{
+    entropy_channel_impl_t *c;
+
+    c = (entropy_channel_impl_t *)oskit_osenv_mem_alloc(mem, sizeof(*c), 0, 0);
+
+    if (c == NULL)
+	return OSKIT_E_OUTOFMEMORY;
+
+    memset(c, 0, sizeof(*c));
+    c->iec.ops = &entropy_channel_ops;
+    c->ep = ep;
+    c->count = 1;
+    *out_chan = (oskit_entropy_channel_t *)c;
+	
+    return 0;
+}
+
+/* End of entropy_channel.c */
diff -ruN oskit-20020317/linux/dev/entropy_driver.h oskit-20020317-entropy/linux/dev/entropy_driver.h
--- oskit-20020317/linux/dev/entropy_driver.h	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/linux/dev/entropy_driver.h	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,28 @@
+
+#ifndef _LINUX_ENTROPY_DRIVER_H_
+#define _LINUX_ENTROPY_DRIVER_H_
+
+#include "glue.h"
+
+struct device
+{
+    char *name;
+    struct device *next;
+    int (*open)(struct device *dev);
+    void *my_alias;
+};
+
+struct entropy_driver {
+    struct driver_struct              ds;
+    oskit_devinfo_t                   dev_info;
+    struct oskit_osenv_entropy_ops    *dev_ops;
+    const char                        *basename;
+    oskit_guid_t                      *dev_iids;
+    int                               dev_niids;
+    int                               (*probe)(struct device *dev);
+};
+
+oskit_error_t oskit_linux_entropy_init(void);
+oskit_error_t oskit_linux_entropy_probe(struct driver_struct *);
+
+#endif /* _LINUX_ENTROPY_DRIVER_H_ */
diff -ruN oskit-20020317/linux/dev/entropy_impl.h oskit-20020317-entropy/linux/dev/entropy_impl.h
--- oskit-20020317/linux/dev/entropy_impl.h	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/linux/dev/entropy_impl.h	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,31 @@
+
+#ifndef _LINUX_DEV_ENTROPY_IMPL_H_
+#define _LINUX_DEV_ENTROPY_IMPL_H_
+
+/*
+ * This code copyright (c) 2002, 2003 Derek L Davies (ddavies@ddavies.net)
+ */
+
+#include <oskit/dev/osenv_mem.h>
+#include <oskit/dev/entropy.h>
+#include <linux/fs.h>
+#include <linux/dcache.h>
+#include "glue.h"
+
+typedef struct entropy_impl {
+    /* COM interface */
+    oskit_entropy_t ie;
+    unsigned int count;
+    oskit_entropy_stats_t stats;
+    oskit_stream_t noblock;
+    oskit_stream_t good;
+    struct file fs;
+    struct dentry des;
+    struct inode in;
+    struct driver_struct *ds;
+#ifndef KNIT
+    oskit_osenv_mem_t *mem;
+#endif
+} entropy_impl_t;
+
+#endif
diff -ruN oskit-20020317/linux/dev/global.h oskit-20020317-entropy/linux/dev/global.h
--- oskit-20020317/linux/dev/global.h	Wed Jan 30 19:40:58 2002
+++ oskit-20020317-entropy/linux/dev/global.h	Thu Jan  2 11:04:43 2003
@@ -871,6 +871,7 @@
 #define fd_routine FDEV_LINUX_fd_routine
 #define linux_softintr_init FDEV_LINUX_linux_softintr_init
 #define softintr_vector FDEV_LINUX_softintr_vector
+#define rand_initialize FDEV_LINUX_rand_initialize
 
 #define signal_pending(current)	0
 
diff -ruN oskit-20020317/linux/dev/init_all.c oskit-20020317-entropy/linux/dev/init_all.c
--- oskit-20020317/linux/dev/init_all.c	Mon Dec  7 06:14:45 1998
+++ oskit-20020317-entropy/linux/dev/init_all.c	Thu Jan  2 11:04:43 2003
@@ -21,4 +21,5 @@
 {
 	oskit_linux_init_blk();
 	oskit_linux_init_net();
+	oskit_linux_init_randompools();
 }
diff -ruN oskit-20020317/linux/dev/init_entropy.c oskit-20020317-entropy/linux/dev/init_entropy.c
--- oskit-20020317/linux/dev/init_entropy.c	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/linux/dev/init_entropy.c	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,11 @@
+
+#include <oskit/dev/linux.h>
+
+#include "glue.h"
+
+void oskit_linux_init_entropy(void)
+{
+#define entropy(name, description, vendor, author, filename, probe) \
+    INIT_DRIVER(entropy_##name, description " Entropy driver");
+#include <oskit/dev/linux_entropy.h>
+}
diff -ruN oskit-20020317/linux/dev/irq.c oskit-20020317-entropy/linux/dev/irq.c
--- oskit-20020317/linux/dev/irq.c	Tue Aug 22 12:46:37 2000
+++ oskit-20020317-entropy/linux/dev/irq.c	Thu Jan  2 11:04:43 2003
@@ -112,6 +112,9 @@
 	if (bh_mask & bh_active)
 		osenv_softirq_schedule(softintr_vector);
 
+	if (handlers[irq]->flags & SA_SAMPLE_RANDOM)
+	    add_interrupt_randomness(irq);
+
 	linux_cli();
 
 	current = cur;
diff -ruN oskit-20020317/linux/dev/misc.c oskit-20020317-entropy/linux/dev/misc.c
--- oskit-20020317/linux/dev/misc.c	Wed Nov 10 19:53:10 1999
+++ oskit-20020317-entropy/linux/dev/misc.c	Thu Jan  2 11:04:43 2003
@@ -27,6 +27,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/time.h>
 #include <linux/module.h>
+#include <linux/dev/block.h>
 
 #include "linux_emul.h"
 #include "osenv.h"
@@ -104,11 +105,6 @@
 	return 0;
 }
 
-void
-add_blkdev_randomness (int major)
-{
-}
-
 int
 dev_get_info (char *buffer, char **start, off_t offset, int length, int dummy)
 {
diff -ruN oskit-20020317/linux/dev/randompool.h oskit-20020317-entropy/linux/dev/randompool.h
--- oskit-20020317/linux/dev/randompool.h	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/linux/dev/randompool.h	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,17 @@
+
+#ifndef _LINUX_RANDOMPOOL_H_
+#define _LINUX_RANDOMPOOL_H_
+
+#include "glue.h"
+
+struct randompool_driver {
+    struct driver_struct              ds;
+    oskit_devinfo_t                   dev_info;
+    struct oskit_osenv_randompool_ops *dev_ops;
+    const char                        *basename;
+    oskit_guid_t                      *dev_iids;
+    int                               dev_niids;
+    void                              (*init)(void);
+};
+
+#endif
diff -ruN oskit-20020317/linux/shared/s_init.c oskit-20020317-entropy/linux/shared/s_init.c
--- oskit-20020317/linux/shared/s_init.c	Fri Dec  3 13:21:18 1999
+++ oskit-20020317-entropy/linux/shared/s_init.c	Thu Jan  2 11:04:43 2003
@@ -118,6 +118,7 @@
 
 #ifdef OSKIT_X86
 	boot_cpu_data.x86 = base_cpuid.family;
+	boot_cpu_data.x86_capability |= X86_FEATURE_TSC; /* Used by random.c */
 #if 0
 	boot_cpu_data.loops_per_sec = loops_per_sec;
 #endif
diff -ruN oskit-20020317/linux/src/drivers/char/random.c oskit-20020317-entropy/linux/src/drivers/char/random.c
--- oskit-20020317/linux/src/drivers/char/random.c	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/linux/src/drivers/char/random.c	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,2007 @@
+/*
+ * random.c -- A strong random number generator
+ *
+ * Version 1.04, last modified 26-Apr-98
+ * 
+ * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998.  All rights
+ * reserved.
+ *
+ * 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, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ * 
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ * 
+ * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
+ */
+
+/*
+ * (now, with legal B.S. out of the way.....) 
+ * 
+ * This routine gathers environmental noise from device drivers, etc.,
+ * and returns good random numbers, suitable for cryptographic use.
+ * Besides the obvious cryptographic uses, these numbers are also good
+ * for seeding TCP sequence numbers, and other places where it is
+ * desirable to have numbers which are not only random, but hard to
+ * predict by an attacker.
+ *
+ * Theory of operation
+ * ===================
+ * 
+ * Computers are very predictable devices.  Hence it is extremely hard
+ * to produce truly random numbers on a computer --- as opposed to
+ * pseudo-random numbers, which can easily generated by using a
+ * algorithm.  Unfortunately, it is very easy for attackers to guess
+ * the sequence of pseudo-random number generators, and for some
+ * applications this is not acceptable.  So instead, we must try to
+ * gather "environmental noise" from the computer's environment, which
+ * must be hard for outside attackers to observe, and use that to
+ * generate random numbers.  In a Unix environment, this is best done
+ * from inside the kernel.
+ * 
+ * Sources of randomness from the environment include inter-keyboard
+ * timings, inter-interrupt timings from some interrupts, and other
+ * events which are both (a) non-deterministic and (b) hard for an
+ * outside observer to measure.  Randomness from these sources are
+ * added to an "entropy pool", which is mixed using a CRC-like function.
+ * This is not cryptographically strong, but it is adequate assuming
+ * the randomness is not chosen maliciously, and it is fast enough that
+ * the overhead of doing it on every interrupt is very reasonable.
+ * As random bytes are mixed into the entropy pool, the routines keep
+ * an *estimate* of how many bits of randomness have been stored into
+ * the random number generator's internal state.
+ * 
+ * When random bytes are desired, they are obtained by taking the SHA
+ * hash of the contents of the "entropy pool".  The SHA hash avoids
+ * exposing the internal state of the entropy pool.  It is believed to
+ * be computationally infeasible to derive any useful information
+ * about the input of SHA from its output.  Even if it is possible to
+ * analyze SHA in some clever way, as long as the amount of data
+ * returned from the generator is less than the inherent entropy in
+ * the pool, the output data is totally unpredictable.  For this
+ * reason, the routine decreases its internal estimate of how many
+ * bits of "true randomness" are contained in the entropy pool as it
+ * outputs random numbers.
+ * 
+ * If this estimate goes to zero, the routine can still generate
+ * random numbers; however, an attacker may (at least in theory) be
+ * able to infer the future output of the generator from prior
+ * outputs.  This requires successful cryptanalysis of SHA, which is
+ * not believed to be feasible, but there is a remote possibility.
+ * Nonetheless, these numbers should be useful for the vast majority
+ * of purposes.
+ * 
+ * Exported interfaces ---- output
+ * ===============================
+ * 
+ * There are three exported interfaces; the first is one designed to
+ * be used from within the kernel:
+ *
+ * 	void get_random_bytes(void *buf, int nbytes);
+ *
+ * This interface will return the requested number of random bytes,
+ * and place it in the requested buffer.
+ * 
+ * The two other interfaces are two character devices /dev/random and
+ * /dev/urandom.  /dev/random is suitable for use when very high
+ * quality randomness is desired (for example, for key generation or
+ * one-time pads), as it will only return a maximum of the number of
+ * bits of randomness (as estimated by the random number generator)
+ * contained in the entropy pool.
+ * 
+ * The /dev/urandom device does not have this limit, and will return
+ * as many bytes as are requested.  As more and more random bytes are
+ * requested without giving time for the entropy pool to recharge,
+ * this will result in random numbers that are merely cryptographically
+ * strong.  For many applications, however, this is acceptable.
+ *
+ * Exported interfaces ---- input
+ * ==============================
+ * 
+ * The current exported interfaces for gathering environmental noise
+ * from the devices are:
+ * 
+ * 	void add_keyboard_randomness(unsigned char scancode);
+ * 	void add_mouse_randomness(__u32 mouse_data);
+ * 	void add_interrupt_randomness(int irq);
+ * 	void add_blkdev_randomness(int irq);
+ * 
+ * add_keyboard_randomness() uses the inter-keypress timing, as well as the
+ * scancode as random inputs into the "entropy pool".
+ * 
+ * add_mouse_randomness() uses the mouse interrupt timing, as well as
+ * the reported position of the mouse from the hardware.
+ *
+ * add_interrupt_randomness() uses the inter-interrupt timing as random
+ * inputs to the entropy pool.  Note that not all interrupts are good
+ * sources of randomness!  For example, the timer interrupts is not a
+ * good choice, because the periodicity of the interrupts is to
+ * regular, and hence predictable to an attacker.  Disk interrupts are
+ * a better measure, since the timing of the disk interrupts are more
+ * unpredictable.
+ * 
+ * add_blkdev_randomness() times the finishing time of block requests.
+ * 
+ * All of these routines try to estimate how many bits of randomness a
+ * particular randomness source.  They do this by keeping track of the
+ * first and second order deltas of the event timings.
+ *
+ * Ensuring unpredictability at system startup
+ * ============================================
+ * 
+ * When any operating system starts up, it will go through a sequence
+ * of actions that are fairly predictable by an adversary, especially
+ * if the start-up does not involve interaction with a human operator.
+ * This reduces the actual number of bits of unpredictability in the
+ * entropy pool below the value in entropy_count.  In order to
+ * counteract this effect, it helps to carry information in the
+ * entropy pool across shut-downs and start-ups.  To do this, put the
+ * following lines an appropriate script which is run during the boot
+ * sequence: 
+ *
+ *	echo "Initializing random number generator..."
+ * 	random_seed=/var/run/random-seed
+ *	# Carry a random seed from start-up to start-up
+ *	# Load and then save 512 bytes, which is the size of the entropy pool
+ * 	if [ -f $random_seed ]; then
+ *		cat $random_seed >/dev/urandom
+ * 	fi
+ *	dd if=/dev/urandom of=$random_seed count=1
+ * 	chmod 600 $random_seed
+ *
+ * and the following lines in an appropriate script which is run as
+ * the system is shutdown:
+ * 
+ *	# Carry a random seed from shut-down to start-up
+ *	# Save 512 bytes, which is the size of the entropy pool
+ *	echo "Saving random seed..."
+ * 	random_seed=/var/run/random-seed
+ *	dd if=/dev/urandom of=$random_seed count=1
+ * 	chmod 600 $random_seed
+ * 
+ * For example, on most modern systems using the System V init
+ * scripts, such code fragments would be found in
+ * /etc/rc.d/init.d/random.  On older Linux systems, the correct script
+ * location might be in /etc/rcb.d/rc.local or /etc/rc.d/rc.0.
+ * 
+ * Effectively, these commands cause the contents of the entropy pool
+ * to be saved at shut-down time and reloaded into the entropy pool at
+ * start-up.  (The 'dd' in the addition to the bootup script is to
+ * make sure that /etc/random-seed is different for every start-up,
+ * even if the system crashes without executing rc.0.)  Even with
+ * complete knowledge of the start-up activities, predicting the state
+ * of the entropy pool requires knowledge of the previous history of
+ * the system.
+ *
+ * Configuring the /dev/random driver under Linux
+ * ==============================================
+ *
+ * The /dev/random driver under Linux uses minor numbers 8 and 9 of
+ * the /dev/mem major number (#1).  So if your system does not have
+ * /dev/random and /dev/urandom created already, they can be created
+ * by using the commands:
+ *
+ * 	mknod /dev/random c 1 8
+ * 	mknod /dev/urandom c 1 9
+ * 
+ * Acknowledgements:
+ * =================
+ *
+ * Ideas for constructing this random number generator were derived
+ * from Pretty Good Privacy's random number generator, and from private
+ * discussions with Phil Karn.  Colin Plumb provided a faster random
+ * number generator, which speed up the mixing function of the entropy
+ * pool, taken from PGPfone.  Dale Worley has also contributed many
+ * useful ideas and suggestions to improve this driver.
+ * 
+ * Any flaws in the design are solely my responsibility, and should
+ * not be attributed to the Phil, Colin, or any of authors of PGP.
+ * 
+ * The code for SHA transform was taken from Peter Gutmann's
+ * implementation, which has been placed in the public domain.
+ * The code for MD5 transform was taken from Colin Plumb's
+ * implementation, which has been placed in the public domain.  The
+ * MD5 cryptographic checksum was devised by Ronald Rivest, and is
+ * documented in RFC 1321, "The MD5 Message Digest Algorithm".
+ * 
+ * Further background information on this topic may be obtained from
+ * RFC 1750, "Randomness Recommendations for Security", by Donald
+ * Eastlake, Steve Crocker, and Jeff Schiller.
+ */
+
+/*
+ * Added a check for signal pending in the extract_entropy() loop to allow
+ * the read(2) syscall to be interrupted. Copyright (C) 1998  Andrea Arcangeli
+ */
+
+/* +++ DLD: Need this for additional members in struct tast_struct
+   so that the 'current' pointer works as expected */
+#define OSKIT_FS
+/* --- DLD */
+
+#include <linux/utsname.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/sched.h> /* DLD: Might be a linux bug.  Need for CURRENT_TIME macro. */
+#include <linux/utsname.h> /* DLD: Might be a linux bug.  Need for struct new_utsname . */
+
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#ifdef OSKIT
+/* +++ DLD */
+
+/* Not sure where this should come from
+*/
+struct new_utsname system_utsname = { "foosys", /* sysname */
+				      "foonode", /* nodename */
+				      "foorel", /* release */
+				      "foover", /* version */
+				      "foomach", /* machine */
+				      "foodom"  /* domainname */
+				     };
+
+/* Stuff that comes from oskit/linux/src/fs, but I dont
+   want to pull everything in, so we just hack it in
+   here.
+*/
+
+/* From inode.c .
+*/
+void __mark_inode_dirty(struct inode *inode)
+{
+    return;
+}
+
+/* From inode.c .
+*/
+void update_atime (struct inode *inode)
+{
+    inode->i_atime = CURRENT_TIME;
+    mark_inode_dirty (inode);
+}
+
+/* From time.c .
+*/
+int
+fs_linux_current_time()
+{
+#if 0 /* DLD: FIXME FIX THIS!! */
+	struct timeval tv, *tvp = &tv;
+	struct task_struct *task;
+
+	task = current;
+	/* Right thing to do? */
+
+	if (gettimeofday(tvp, 0))
+		panic("fs_linux_current_time: gettimeofday failed");
+	current = task;
+
+	while (tvp->tv_usec > 1000000) {
+		tvp->tv_sec++;
+		tvp->tv_usec -= 1000000;
+	}
+
+	return tv.tv_sec;
+#else
+	return 0;
+#endif /* FIXME */
+}
+#endif
+
+#ifdef OSKIT
+  #define FROBLINKAGE extern
+#else
+  #define FROBLINKAGE static
+#endif
+/* --- DLD */
+
+/*
+ * Configuration information
+ */
+#undef RANDOM_BENCHMARK
+#undef BENCHMARK_NOINT
+#define ROTATE_PARANOIA
+
+/* DLD: Can go only as low as 32 */
+#define POOLWORDS 128    /* Power of 2 - note that this is 32-bit words */
+#define POOLBITS (POOLWORDS*32)
+/*
+ * The pool is stirred with a primitive polynomial of degree POOLWORDS
+ * over GF(2).  The taps for various sizes are defined below.  They are
+ * chosen to be evenly spaced (minimum RMS distance from evenly spaced;
+ * the numbers in the comments are a scaled squared error sum) except
+ * for the last tap, which is 1 to get the twisting happening as fast
+ * as possible.
+ */
+#if POOLWORDS == 2048	/* 115 x^2048+x^1638+x^1231+x^819+x^411+x^1+1 */
+#define TAP1	1638
+#define TAP2	1231
+#define TAP3	819
+#define TAP4	411
+#define TAP5	1
+#elif POOLWORDS == 1024	/* 290 x^1024+x^817+x^615+x^412+x^204+x^1+1 */
+/* Alt: 115 x^1024+x^819+x^616+x^410+x^207+x^2+1 */
+#define TAP1	817
+#define TAP2	615
+#define TAP3	412
+#define TAP4	204
+#define TAP5	1
+#elif POOLWORDS == 512	/* 225 x^512+x^411+x^308+x^208+x^104+x+1 */
+/* Alt: 95 x^512+x^409+x^307+x^206+x^102+x^2+1
+ *      95 x^512+x^409+x^309+x^205+x^103+x^2+1 */
+#define TAP1	411
+#define TAP2	308
+#define TAP3	208
+#define TAP4	104
+#define TAP5	1
+#elif POOLWORDS == 256	/* 125 x^256+x^205+x^155+x^101+x^52+x+1 */
+#define TAP1	205
+#define TAP2	155
+#define TAP3	101
+#define TAP4	52
+#define TAP5	1
+#elif POOLWORDS == 128	/* 105 x^128+x^103+x^76+x^51+x^25+x+1 */
+/* Alt: 70 x^128+x^103+x^78+x^51+x^27+x^2+1 */
+#define TAP1	103
+#define TAP2	76
+#define TAP3	51
+#define TAP4	25
+#define TAP5	1
+#elif POOLWORDS == 64	/* 15 x^64+x^52+x^39+x^26+x^14+x+1 */
+#define TAP1	52
+#define TAP2	39
+#define TAP3	26
+#define TAP4	14
+#define TAP5	1
+#elif POOLWORDS == 32	/* 15 x^32+x^26+x^20+x^14+x^7+x^1+1 */
+#define TAP1	26
+#define TAP2	20
+#define TAP3	14
+#define TAP4	7
+#define TAP5	1
+#elif POOLWORDS & (POOLWORDS-1)
+#error POOLWORDS must be a power of 2
+#else
+#error No primitive polynomial available for chosen POOLWORDS
+#endif
+
+/*
+ * For the purposes of better mixing, we use the CRC-32 polynomial as
+ * well to make a twisted Generalized Feedback Shift Reigster
+ *
+ * (See M. Matsumoto & Y. Kurita, 1992.  Twisted GFSR generators.  ACM
+ * Transactions on Modeling and Computer Simulation 2(3):179-194.
+ * Also see M. Matsumoto & Y. Kurita, 1994.  Twisted GFSR generators
+ * II.  ACM Transactions on Mdeling and Computer Simulation 4:254-266)
+ *
+ * Thanks to Colin Plumb for suggesting this.
+ * We have not analyzed the resultant polynomial to prove it primitive;
+ * in fact it almost certainly isn't.  Nonetheless, the irreducible factors
+ * of a random large-degree polynomial over GF(2) are more than large enough
+ * that periodicity is not a concern.
+ *
+ * The input hash is much less sensitive than the output hash.  All that
+ * we want of it is that it be a good non-cryptographic hash; i.e. it
+ * not produce collisions when fed "random" data of the sort we expect
+ * to see.  As long as the pool state differs for different inputs, we
+ * have preserved the input entropy and done a good job.  The fact that an
+ * intelligent attacker can construct inputs that will produce controlled
+ * alterations to the pool's state is not important because we don't
+ * consider such inputs to contribute any randomness.
+ * The only property we need with respect to them is
+ * that the attacker can't increase his/her knowledge of the pool's state.
+ * Since all additions are reversible (knowing the final state and the
+ * input, you can reconstruct the initial state), if an attacker has
+ * any uncertainty about the initial state, he/she can only shuffle that
+ * uncertainty about, but never cause any collisions (which would
+ * decrease the uncertainty).
+ *
+ * The chosen system lets the state of the pool be (essentially) the input
+ * modulo the generator polymnomial.  Now, for random primitive polynomials,
+ * this is a universal class of hash functions, meaning that the chance
+ * of a collision is limited by the attacker's knowledge of the generator
+ * polynomail, so if it is chosen at random, an attacker can never force
+ * a collision.  Here, we use a fixed polynomial, but we *can* assume that
+ * ###--> it is unknown to the processes generating the input entropy. <-###
+ * Because of this important property, this is a good, collision-resistant
+ * hash; hash collisions will occur no more often than chance.
+ */
+
+/*
+ * The minimum number of bits to release a "wait on input".  Should
+ * probably always be 8, since a /dev/random read can return a single
+ * byte.
+ */
+#define WAIT_INPUT_BITS 8
+/* 
+ * The limit number of bits under which to release a "wait on
+ * output".  Should probably always be the same as WAIT_INPUT_BITS, so
+ * that an output wait releases when and only when a wait on input
+ * would block.
+ */
+#define WAIT_OUTPUT_BITS WAIT_INPUT_BITS
+
+/* There is actually only one of these, globally. */
+struct random_bucket {
+	unsigned add_ptr;
+	unsigned entropy_count;
+#ifdef ROTATE_PARANOIA	
+	int input_rotate;
+#endif
+	__u32 pool[POOLWORDS];
+};
+
+#ifdef RANDOM_BENCHMARK
+/* For benchmarking only */
+struct random_benchmark {
+	unsigned long long 	start_time;
+	int			times;		/* # of samples */
+	unsigned long		min;
+	unsigned long		max;
+	unsigned long		accum;		/* accumulator for average */
+	const char		*descr;
+	int			unit;
+	unsigned long		flags;
+};
+
+#define BENCHMARK_INTERVAL 500
+
+static void initialize_benchmark(struct random_benchmark *bench,
+				 const char *descr, int unit);
+static void begin_benchmark(struct random_benchmark *bench);
+static void end_benchmark(struct random_benchmark *bench);
+
+struct random_benchmark timer_benchmark;
+#endif
+
+/* There is one of these per entropy source */
+struct timer_rand_state {
+	__u32		last_time;
+	__s32		last_delta,last_delta2;
+	int		dont_count_entropy:1;
+};
+
+static struct random_bucket random_state;
+static struct timer_rand_state keyboard_timer_state;
+static struct timer_rand_state mouse_timer_state;
+static struct timer_rand_state extract_timer_state;
+static struct timer_rand_state *irq_timer_state[NR_IRQS];
+static struct timer_rand_state *blkdev_timer_state[MAX_BLKDEV];
+static struct wait_queue *random_read_wait;
+static struct wait_queue *random_write_wait;
+
+FROBLINKAGE ssize_t random_read(struct file * file, char * buf,
+			   size_t nbytes, loff_t *ppos);
+FROBLINKAGE ssize_t random_read_unlimited(struct file * file, char * buf,
+				     size_t nbytes, loff_t *ppos);
+static unsigned int random_poll(struct file *file, poll_table * wait);
+FROBLINKAGE ssize_t random_write(struct file * file, const char * buffer,
+			    size_t count, loff_t *ppos);
+FROBLINKAGE int random_ioctl(struct inode * inode, struct file * file,
+			     unsigned int cmd, unsigned long arg);
+
+static inline void fast_add_entropy_words(struct random_bucket *r,
+					 __u32 x, __u32 y);
+
+static void add_entropy_words(struct random_bucket *r, __u32 x, __u32 y);
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/*
+ * Unfortunately, while the GCC optimizer for the i386 understands how
+ * to optimize a static rotate left of x bits, it doesn't know how to
+ * deal with a variable rotate of x bits.  So we use a bit of asm magic.
+ */
+#if (!defined (__i386__))
+extern inline __u32 rotate_left(int i, __u32 word)
+{
+	return (word << i) | (word >> (32 - i));
+	
+}
+#else
+extern inline __u32 rotate_left(int i, __u32 word)
+{
+	__asm__("roll %%cl,%0"
+		:"=r" (word)
+		:"0" (word),"c" (i));
+	return word;
+}
+#endif
+
+/*
+ * More asm magic....
+ * 
+ * For entropy estimation, we need to do an integral base 2
+ * logarithm.  
+ *
+ * Note the "12bits" suffix - this is used for numbers between
+ * 0 and 4095 only.  This allows a few shortcuts.
+ */
+#if 0	/* Slow but clear version */
+static inline __u32 int_ln_12bits(__u32 word)
+{
+	__u32 nbits = 0;
+	
+	while (word >>= 1)
+		nbits++;
+	return nbits;
+}
+#else	/* Faster (more clever) version, courtesy Colin Plumb */
+static inline __u32 int_ln_12bits(__u32 word)
+{
+	/* Smear msbit right to make an n-bit mask */
+	word |= word >> 8;
+	word |= word >> 4;
+	word |= word >> 2;
+	word |= word >> 1;
+	/* Remove one bit to make this a logarithm */
+	word >>= 1;
+	/* Count the bits set in the word */
+	word -= (word >> 1) & 0x555;
+	word = (word & 0x333) + ((word >> 2) & 0x333);
+	word += (word >> 4);
+	word += (word >> 8);
+	return word & 15;
+}
+#endif
+
+	
+/*
+ * Initialize the random pool with standard stuff.
+ *
+ * NOTE: This is an OS-dependent function.
+ */
+static void init_std_data(struct random_bucket *r)
+{
+	__u32 words[2], *p;
+	int i;
+	struct timeval 	tv;
+
+	do_gettimeofday(&tv);
+	add_entropy_words(r, tv.tv_sec, tv.tv_usec);
+
+	/*
+	 *	This doesnt lock system.utsname. Howeve we are generating
+	 *	entropy so a race with a name set here is fine.
+	 */
+	p = (__u32 *)&system_utsname;
+	for (i = sizeof(system_utsname) / sizeof(words); i; i--) {
+		memcpy(words, p, sizeof(words));
+		add_entropy_words(r, words[0], words[1]);
+		p += sizeof(words)/sizeof(*words);
+	}
+}
+
+/* Clear the entropy pool and associated counters. */
+static void rand_clear_pool(void)
+{
+	memset(&random_state, 0, sizeof(random_state));
+	init_std_data(&random_state);
+}
+
+__initfunc(void rand_initialize(void))
+{
+	int i;
+
+	rand_clear_pool();
+	for (i = 0; i < NR_IRQS; i++)
+		irq_timer_state[i] = NULL;
+	for (i = 0; i < MAX_BLKDEV; i++)
+		blkdev_timer_state[i] = NULL;
+	memset(&keyboard_timer_state, 0, sizeof(struct timer_rand_state));
+	memset(&mouse_timer_state, 0, sizeof(struct timer_rand_state));
+	memset(&extract_timer_state, 0, sizeof(struct timer_rand_state));
+#ifdef RANDOM_BENCHMARK
+	initialize_benchmark(&timer_benchmark, "timer", 0);
+#endif
+	extract_timer_state.dont_count_entropy = 1;
+	random_read_wait = NULL;
+	random_write_wait = NULL;
+}
+
+void rand_initialize_irq(int irq)
+{
+	struct timer_rand_state *state;
+	
+	if (irq >= NR_IRQS || irq_timer_state[irq])
+		return;
+
+	/*
+	 * If kmalloc returns null, we just won't use that entropy
+	 * source.
+	 */
+	state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
+	if (state) {
+		irq_timer_state[irq] = state;
+		memset(state, 0, sizeof(struct timer_rand_state));
+	}
+}
+
+void rand_initialize_blkdev(int major, int mode)
+{
+	struct timer_rand_state *state;
+	
+	if (major >= MAX_BLKDEV || blkdev_timer_state[major])
+		return;
+
+	/*
+	 * If kmalloc returns null, we just won't use that entropy
+	 * source.
+	 */
+	state = kmalloc(sizeof(struct timer_rand_state), mode);
+	if (state) {
+		blkdev_timer_state[major] = state;
+		memset(state, 0, sizeof(struct timer_rand_state));
+	}
+}
+
+/*
+ * This function adds a byte into the entropy "pool".  It does not
+ * update the entropy estimate.  The caller must do this if appropriate.
+ *
+ * This function is tuned for speed above most other considerations.
+ *
+ * The pool is stirred with a primitive polynomial of the appropriate degree,
+ * and then twisted.  We twist by three bits at a time because it's
+ * cheap to do so and helps slightly in the expected case where the
+ * entropy is concentrated in the low-order bits.
+ */
+#define MASK(x) ((x) & (POOLWORDS-1))	/* Convenient abreviation */
+static inline void fast_add_entropy_words(struct random_bucket *r,
+					 __u32 x, __u32 y)
+{
+	static __u32 const twist_table[8] = {
+		         0, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+		0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
+	unsigned i, j;
+
+	i = MASK(r->add_ptr - 2);	/* i is always even */
+	r->add_ptr = i;
+
+#ifdef ROTATE_PARANOIA
+	j = r->input_rotate + 14;
+	if (i)
+		j -= 7;
+	r->input_rotate = j & 31;
+
+	x = rotate_left(r->input_rotate, x);
+	y = rotate_left(r->input_rotate, y);
+#endif
+
+	/*
+	 * XOR in the various taps.  Even though logically, we compute
+	 * x and then compute y, we read in y then x order because most
+	 * caches work slightly better with increasing read addresses.
+	 * If a tap is even then we can use the fact that i is even to
+	 * avoid a masking operation.  Every polynomial has at least one
+	 * even tap, so j is always used.
+	 * (Is there a nicer way to arrange this code?)
+	 */
+#if TAP1 & 1
+	y ^= r->pool[MASK(i+TAP1)];	x ^= r->pool[MASK(i+TAP1+1)];
+#else
+	j = MASK(i+TAP1);	y ^= r->pool[j];	x ^= r->pool[j+1];
+#endif
+#if TAP2 & 1
+	y ^= r->pool[MASK(i+TAP2)];	x ^= r->pool[MASK(i+TAP2+1)];
+#else
+	j = MASK(i+TAP2);	y ^= r->pool[j];	x ^= r->pool[j+1];
+#endif
+#if TAP3 & 1
+	y ^= r->pool[MASK(i+TAP3)];	x ^= r->pool[MASK(i+TAP3+1)];
+#else
+	j = MASK(i+TAP3);	y ^= r->pool[j];	x ^= r->pool[j+1];
+#endif
+#if TAP4 & 1
+	y ^= r->pool[MASK(i+TAP4)];	x ^= r->pool[MASK(i+TAP4+1)];
+#else
+	j = MASK(i+TAP4);	y ^= r->pool[j];	x ^= r->pool[j+1];
+#endif
+#if TAP5 == 1
+	/* We need to pretend to write pool[i+1] before computing y */
+	y ^= r->pool[i];
+	x ^= r->pool[i+1];
+	x ^= r->pool[MASK(i+TAP5+1)];
+	y ^= r->pool[i+1] = x = (x >> 3) ^ twist_table[x & 7];
+	r->pool[i] = (y >> 3) ^ twist_table[y & 7];
+#else
+# if TAP5 & 1
+	y ^= r->pool[MASK(i+TAP5)];	x ^= r->pool[MASK(i+TAP5+1)];
+# else
+	j = MASK(i+TAP5);	y ^= r->pool[j];	x ^= r->pool[j+1];
+# endif
+	y ^= r->pool[i];
+	x ^= r->pool[i+1];
+	r->pool[i] = (y >> 3) ^ twist_table[y & 7];
+	r->pool[i+1] = (x >> 3) ^ twist_table[x & 7];
+#endif
+}
+
+/*
+ * For places where we don't need the inlined version
+ */
+static void add_entropy_words(struct random_bucket *r, __u32 x, __u32 y)
+{
+	fast_add_entropy_words(r, x, y);
+}
+
+/*
+ * This function adds entropy to the entropy "pool" by using timing
+ * delays.  It uses the timer_rand_state structure to make an estimate
+ * of how many bits of entropy this call has added to the pool.
+ *
+ * The number "num" is also added to the pool - it should somehow describe
+ * the type of event which just happened.  This is currently 0-255 for
+ * keyboard scan codes, and 256 upwards for interrupts.
+ * On the i386, this is assumed to be at most 16 bits, and the high bits
+ * are used for a high-resolution timer.
+ *
+ */
+static void add_timer_randomness(struct random_bucket *r,
+				 struct timer_rand_state *state, unsigned num)
+{
+	__u32		time;
+	__s32		delta, delta2, delta3;
+
+#ifdef RANDOM_BENCHMARK
+	begin_benchmark(&timer_benchmark);
+#endif
+#if defined (__i386__)
+	if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
+		__u32 high;
+		__asm__(".byte 0x0f,0x31"
+			:"=a" (time), "=d" (high));
+		num ^= high;
+	} else {
+		time = jiffies;
+	}
+#else
+	time = jiffies;
+#endif
+
+	fast_add_entropy_words(r, (__u32)num, time);
+	
+	/*
+	 * Calculate number of bits of randomness we probably added.
+	 * We take into account the first, second and third-order deltas
+	 * in order to make our estimate.
+	 */
+	if ((r->entropy_count < POOLBITS) && !state->dont_count_entropy) {
+		delta = time - state->last_time;
+		state->last_time = time;
+
+		delta2 = delta - state->last_delta;
+		state->last_delta = delta;
+
+		delta3 = delta2 - state->last_delta2;
+		state->last_delta2 = delta2;
+
+		if (delta < 0)
+			delta = -delta;
+		if (delta2 < 0)
+			delta2 = -delta2;
+		if (delta3 < 0)
+			delta3 = -delta3;
+		if (delta > delta2)
+			delta = delta2;
+		if (delta > delta3)
+			delta = delta3;
+
+		/*
+		 * delta is now minimum absolute delta.
+		 * Round down by 1 bit on general principles,
+		 * and limit entropy entimate to 12 bits.
+		 */
+		delta >>= 1;
+		delta &= (1 << 12) - 1;
+
+		r->entropy_count += int_ln_12bits(delta);
+
+		/* Prevent overflow */
+		if (r->entropy_count > POOLBITS)
+			r->entropy_count = POOLBITS;
+
+		/* Wake up waiting processes, if we have enough entropy. */
+		if (r->entropy_count >= WAIT_INPUT_BITS)
+			wake_up_interruptible(&random_read_wait);
+	}
+		
+#ifdef RANDOM_BENCHMARK
+	end_benchmark(&timer_benchmark);
+#endif
+}
+
+void add_keyboard_randomness(unsigned char scancode)
+{
+	add_timer_randomness(&random_state, &keyboard_timer_state, scancode);
+}
+
+void add_mouse_randomness(__u32 mouse_data)
+{
+	add_timer_randomness(&random_state, &mouse_timer_state, mouse_data);
+}
+
+void add_interrupt_randomness(int irq)
+{
+	if (irq >= NR_IRQS || irq_timer_state[irq] == 0)
+		return;
+
+	add_timer_randomness(&random_state, irq_timer_state[irq], 0x100+irq);
+}
+
+void add_blkdev_randomness(int major)
+{
+    /* printf("Hello from linux random driver add_blkdev_randomness\n");*/
+    /* DLD: Mon Oct 14 21:03:45 2002
+       There is a problem here.  The ide_end_request function in linux/src/drivers/block/ide.c
+       calls this function unconditionally.  So we need to know here (or somewhere) if the
+       block device was registered with the randompool and, if so, do nothing.
+    */
+	if (major >= MAX_BLKDEV)
+		return;
+
+	if (blkdev_timer_state[major] == 0) {
+		rand_initialize_blkdev(major, GFP_ATOMIC);
+		if (blkdev_timer_state[major] == 0)
+			return;
+	}
+		
+	add_timer_randomness(&random_state, blkdev_timer_state[major],
+			     0x200+major);
+}
+
+/*
+ * This chunk of code defines a function
+ * void HASH_TRANSFORM(__u32 digest[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE],
+ * 		__u32 const data[16])
+ * 
+ * The function hashes the input data to produce a digest in the first
+ * HASH_BUFFER_SIZE words of the digest[] array, and uses HASH_EXTRA_SIZE
+ * more words for internal purposes.  (This buffer is exported so the
+ * caller can wipe it once rather than this code doing it each call,
+ * and tacking it onto the end of the digest[] array is the quick and
+ * dirty way of doing it.)
+ *
+ * It so happens that MD5 and SHA share most of the initial vector
+ * used to initialize the digest[] array before the first call:
+ * 1) 0x67452301
+ * 2) 0xefcdab89
+ * 3) 0x98badcfe
+ * 4) 0x10325476
+ * 5) 0xc3d2e1f0 (SHA only)
+ *
+ * For /dev/random purposes, the length of the data being hashed is
+ * fixed in length (at POOLWORDS words), so appending a bit count in
+ * the usual way is not cryptographically necessary.
+ */
+#define USE_SHA
+
+#ifdef USE_SHA
+
+#define HASH_BUFFER_SIZE 5
+#define HASH_EXTRA_SIZE 80
+#define HASH_TRANSFORM SHATransform
+
+/* Various size/speed tradeoffs are available.  Choose 0..3. */
+#define SHA_CODE_SIZE 0
+
+/*
+ * SHA transform algorithm, taken from code written by Peter Gutmann,
+ * and placed in the public domain.
+ */
+
+/* The SHA f()-functions.  */
+
+#define f1(x,y,z)   ( z ^ (x & (y^z)) )		/* Rounds  0-19: x ? y : z */
+#define f2(x,y,z)   (x ^ y ^ z)			/* Rounds 20-39: XOR */
+#define f3(x,y,z)   ( (x & y) + (z & (x ^ y)) )	/* Rounds 40-59: majority */
+#define f4(x,y,z)   (x ^ y ^ z)			/* Rounds 60-79: XOR */
+
+/* The SHA Mysterious Constants */
+
+#define K1  0x5A827999L			/* Rounds  0-19: sqrt(2) * 2^30 */
+#define K2  0x6ED9EBA1L			/* Rounds 20-39: sqrt(3) * 2^30 */
+#define K3  0x8F1BBCDCL			/* Rounds 40-59: sqrt(5) * 2^30 */
+#define K4  0xCA62C1D6L			/* Rounds 60-79: sqrt(10) * 2^30 */
+
+#define ROTL(n,X)  ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
+
+#define subRound(a, b, c, d, e, f, k, data) \
+    ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) )
+
+
+static void SHATransform(__u32 digest[85], __u32 const data[16])
+{
+    __u32 A, B, C, D, E;     /* Local vars */
+    __u32 TEMP;
+    int	i;
+#define W (digest + HASH_BUFFER_SIZE)	/* Expanded data array */
+
+    /*
+     * Do the preliminary expansion of 16 to 80 words.  Doing it
+     * out-of-line line this is faster than doing it in-line on
+     * register-starved machines like the x86, and not really any
+     * slower on real processors.
+     */
+    memcpy(W, data, 16*sizeof(__u32));
+    for (i = 0; i < 64; i++) {
+	    TEMP = W[i] ^ W[i+2] ^ W[i+8] ^ W[i+13];
+	    W[i+16] = ROTL(1, TEMP);
+    }
+
+    /* Set up first buffer and local data buffer */
+    A = digest[ 0 ];
+    B = digest[ 1 ];
+    C = digest[ 2 ];
+    D = digest[ 3 ];
+    E = digest[ 4 ];
+
+    /* Heavy mangling, in 4 sub-rounds of 20 iterations each. */
+#if SHA_CODE_SIZE == 0
+    /*
+     * Approximately 50% of the speed of the largest version, but
+     * takes up 1/16 the space.  Saves about 6k on an i386 kernel.
+     */
+    for (i = 0; i < 80; i++) {
+	if (i < 40) {
+	    if (i < 20)
+		TEMP = f1(B, C, D) + K1;
+	    else
+		TEMP = f2(B, C, D) + K2;
+	} else {
+	    if (i < 60)
+		TEMP = f3(B, C, D) + K3;
+	    else
+		TEMP = f4(B, C, D) + K4;
+	}
+	TEMP += ROTL(5, A) + E + W[i];
+	E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+    }
+#elif SHA_CODE_SIZE == 1
+    for (i = 0; i < 20; i++) {
+	TEMP = f1(B, C, D) + K1 + ROTL(5, A) + E + W[i];
+	E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+    }
+    for (; i < 40; i++) {
+	TEMP = f2(B, C, D) + K2 + ROTL(5, A) + E + W[i];
+	E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+    }
+    for (; i < 60; i++) {
+	TEMP = f3(B, C, D) + K3 + ROTL(5, A) + E + W[i];
+	E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+    }
+    for (; i < 80; i++) {
+	TEMP = f4(B, C, D) + K4 + ROTL(5, A) + E + W[i];
+	E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+    }
+#elif SHA_CODE_SIZE == 2
+    for (i = 0; i < 20; i += 5) {
+	subRound( A, B, C, D, E, f1, K1, W[ i   ] );
+	subRound( E, A, B, C, D, f1, K1, W[ i+1 ] );
+	subRound( D, E, A, B, C, f1, K1, W[ i+2 ] );
+	subRound( C, D, E, A, B, f1, K1, W[ i+3 ] );
+	subRound( B, C, D, E, A, f1, K1, W[ i+4 ] );
+    }
+    for (; i < 40; i += 5) {
+	subRound( A, B, C, D, E, f2, K2, W[ i   ] );
+	subRound( E, A, B, C, D, f2, K2, W[ i+1 ] );
+	subRound( D, E, A, B, C, f2, K2, W[ i+2 ] );
+	subRound( C, D, E, A, B, f2, K2, W[ i+3 ] );
+	subRound( B, C, D, E, A, f2, K2, W[ i+4 ] );
+    }
+    for (; i < 60; i += 5) {
+	subRound( A, B, C, D, E, f3, K3, W[ i   ] );
+	subRound( E, A, B, C, D, f3, K3, W[ i+1 ] );
+	subRound( D, E, A, B, C, f3, K3, W[ i+2 ] );
+	subRound( C, D, E, A, B, f3, K3, W[ i+3 ] );
+	subRound( B, C, D, E, A, f3, K3, W[ i+4 ] );
+    }
+    for (; i < 80; i += 5) {
+	subRound( A, B, C, D, E, f4, K4, W[ i   ] );
+	subRound( E, A, B, C, D, f4, K4, W[ i+1 ] );
+	subRound( D, E, A, B, C, f4, K4, W[ i+2 ] );
+	subRound( C, D, E, A, B, f4, K4, W[ i+3 ] );
+	subRound( B, C, D, E, A, f4, K4, W[ i+4 ] );
+    }
+#elif SHA_CODE_SIZE == 3 /* Really large version */
+    subRound( A, B, C, D, E, f1, K1, W[  0 ] );
+    subRound( E, A, B, C, D, f1, K1, W[  1 ] );
+    subRound( D, E, A, B, C, f1, K1, W[  2 ] );
+    subRound( C, D, E, A, B, f1, K1, W[  3 ] );
+    subRound( B, C, D, E, A, f1, K1, W[  4 ] );
+    subRound( A, B, C, D, E, f1, K1, W[  5 ] );
+    subRound( E, A, B, C, D, f1, K1, W[  6 ] );
+    subRound( D, E, A, B, C, f1, K1, W[  7 ] );
+    subRound( C, D, E, A, B, f1, K1, W[  8 ] );
+    subRound( B, C, D, E, A, f1, K1, W[  9 ] );
+    subRound( A, B, C, D, E, f1, K1, W[ 10 ] );
+    subRound( E, A, B, C, D, f1, K1, W[ 11 ] );
+    subRound( D, E, A, B, C, f1, K1, W[ 12 ] );
+    subRound( C, D, E, A, B, f1, K1, W[ 13 ] );
+    subRound( B, C, D, E, A, f1, K1, W[ 14 ] );
+    subRound( A, B, C, D, E, f1, K1, W[ 15 ] );
+    subRound( E, A, B, C, D, f1, K1, W[ 16 ] );
+    subRound( D, E, A, B, C, f1, K1, W[ 17 ] );
+    subRound( C, D, E, A, B, f1, K1, W[ 18 ] );
+    subRound( B, C, D, E, A, f1, K1, W[ 19 ] );
+
+    subRound( A, B, C, D, E, f2, K2, W[ 20 ] );
+    subRound( E, A, B, C, D, f2, K2, W[ 21 ] );
+    subRound( D, E, A, B, C, f2, K2, W[ 22 ] );
+    subRound( C, D, E, A, B, f2, K2, W[ 23 ] );
+    subRound( B, C, D, E, A, f2, K2, W[ 24 ] );
+    subRound( A, B, C, D, E, f2, K2, W[ 25 ] );
+    subRound( E, A, B, C, D, f2, K2, W[ 26 ] );
+    subRound( D, E, A, B, C, f2, K2, W[ 27 ] );
+    subRound( C, D, E, A, B, f2, K2, W[ 28 ] );
+    subRound( B, C, D, E, A, f2, K2, W[ 29 ] );
+    subRound( A, B, C, D, E, f2, K2, W[ 30 ] );
+    subRound( E, A, B, C, D, f2, K2, W[ 31 ] );
+    subRound( D, E, A, B, C, f2, K2, W[ 32 ] );
+    subRound( C, D, E, A, B, f2, K2, W[ 33 ] );
+    subRound( B, C, D, E, A, f2, K2, W[ 34 ] );
+    subRound( A, B, C, D, E, f2, K2, W[ 35 ] );
+    subRound( E, A, B, C, D, f2, K2, W[ 36 ] );
+    subRound( D, E, A, B, C, f2, K2, W[ 37 ] );
+    subRound( C, D, E, A, B, f2, K2, W[ 38 ] );
+    subRound( B, C, D, E, A, f2, K2, W[ 39 ] );
+    
+    subRound( A, B, C, D, E, f3, K3, W[ 40 ] );
+    subRound( E, A, B, C, D, f3, K3, W[ 41 ] );
+    subRound( D, E, A, B, C, f3, K3, W[ 42 ] );
+    subRound( C, D, E, A, B, f3, K3, W[ 43 ] );
+    subRound( B, C, D, E, A, f3, K3, W[ 44 ] );
+    subRound( A, B, C, D, E, f3, K3, W[ 45 ] );
+    subRound( E, A, B, C, D, f3, K3, W[ 46 ] );
+    subRound( D, E, A, B, C, f3, K3, W[ 47 ] );
+    subRound( C, D, E, A, B, f3, K3, W[ 48 ] );
+    subRound( B, C, D, E, A, f3, K3, W[ 49 ] );
+    subRound( A, B, C, D, E, f3, K3, W[ 50 ] );
+    subRound( E, A, B, C, D, f3, K3, W[ 51 ] );
+    subRound( D, E, A, B, C, f3, K3, W[ 52 ] );
+    subRound( C, D, E, A, B, f3, K3, W[ 53 ] );
+    subRound( B, C, D, E, A, f3, K3, W[ 54 ] );
+    subRound( A, B, C, D, E, f3, K3, W[ 55 ] );
+    subRound( E, A, B, C, D, f3, K3, W[ 56 ] );
+    subRound( D, E, A, B, C, f3, K3, W[ 57 ] );
+    subRound( C, D, E, A, B, f3, K3, W[ 58 ] );
+    subRound( B, C, D, E, A, f3, K3, W[ 59 ] );
+
+    subRound( A, B, C, D, E, f4, K4, W[ 60 ] );
+    subRound( E, A, B, C, D, f4, K4, W[ 61 ] );
+    subRound( D, E, A, B, C, f4, K4, W[ 62 ] );
+    subRound( C, D, E, A, B, f4, K4, W[ 63 ] );
+    subRound( B, C, D, E, A, f4, K4, W[ 64 ] );
+    subRound( A, B, C, D, E, f4, K4, W[ 65 ] );
+    subRound( E, A, B, C, D, f4, K4, W[ 66 ] );
+    subRound( D, E, A, B, C, f4, K4, W[ 67 ] );
+    subRound( C, D, E, A, B, f4, K4, W[ 68 ] );
+    subRound( B, C, D, E, A, f4, K4, W[ 69 ] );
+    subRound( A, B, C, D, E, f4, K4, W[ 70 ] );
+    subRound( E, A, B, C, D, f4, K4, W[ 71 ] );
+    subRound( D, E, A, B, C, f4, K4, W[ 72 ] );
+    subRound( C, D, E, A, B, f4, K4, W[ 73 ] );
+    subRound( B, C, D, E, A, f4, K4, W[ 74 ] );
+    subRound( A, B, C, D, E, f4, K4, W[ 75 ] );
+    subRound( E, A, B, C, D, f4, K4, W[ 76 ] );
+    subRound( D, E, A, B, C, f4, K4, W[ 77 ] );
+    subRound( C, D, E, A, B, f4, K4, W[ 78 ] );
+    subRound( B, C, D, E, A, f4, K4, W[ 79 ] );
+#else
+#error Illegal SHA_CODE_SIZE
+#endif
+
+    /* Build message digest */
+    digest[ 0 ] += A;
+    digest[ 1 ] += B;
+    digest[ 2 ] += C;
+    digest[ 3 ] += D;
+    digest[ 4 ] += E;
+
+	/* W is wiped by the caller */
+#undef W
+}
+
+#undef ROTL
+#undef f1
+#undef f2
+#undef f3
+#undef f4
+#undef K1	
+#undef K2
+#undef K3	
+#undef K4	
+#undef subRound
+	
+#else /* !USE_SHA - Use MD5 */
+
+#define HASH_BUFFER_SIZE 4
+#define HASH_EXTRA_SIZE 0
+#define HASH_TRANSFORM MD5Transform
+	
+/*
+ * MD5 transform algorithm, taken from code written by Colin Plumb,
+ * and put into the public domain
+ *
+ * QUESTION: Replace this with SHA, which as generally received better
+ * reviews from the cryptographic community?
+ */
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(__u32 buf[HASH_BUFFER_SIZE], __u32 const in[16])
+{
+	__u32 a, b, c, d;
+
+	a = buf[0];
+	b = buf[1];
+	c = buf[2];
+	d = buf[3];
+
+	MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
+	MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
+	MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
+	MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
+	MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
+	MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
+	MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
+	MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
+	MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
+	MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
+	MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
+	MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
+	MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
+	MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
+	MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
+	MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
+	MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
+	MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
+	MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
+	MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
+	MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+
+#undef F1
+#undef F2
+#undef F3
+#undef F4
+#undef MD5STEP
+
+#endif /* !USE_SHA */
+
+
+#if POOLWORDS % 16 != 0
+#error extract_entropy() assumes that POOLWORDS is a multiple of 16 words.
+#endif
+/*
+ * This function extracts randomness from the "entropy pool", and
+ * returns it in a buffer.  This function computes how many remaining
+ * bits of entropy are left in the pool, but it does not restrict the
+ * number of bytes that are actually obtained.
+ */
+static ssize_t extract_entropy(struct random_bucket *r, char * buf,
+			       size_t nbytes, int to_user)
+{
+	ssize_t ret, i;
+	__u32 tmp[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
+	__u32 x;
+
+	add_timer_randomness(r, &extract_timer_state, nbytes);
+	
+	/* Redundant, but just in case... */
+	if (r->entropy_count > POOLBITS) 
+		r->entropy_count = POOLBITS;
+
+	ret = nbytes;
+	if (r->entropy_count / 8 >= nbytes)
+		r->entropy_count -= nbytes*8;
+	else
+		r->entropy_count = 0;
+
+	if (r->entropy_count < WAIT_OUTPUT_BITS)
+		wake_up_interruptible(&random_write_wait);
+	
+	while (nbytes) {
+		/* Hash the pool to get the output */
+		tmp[0] = 0x67452301;
+		tmp[1] = 0xefcdab89;
+		tmp[2] = 0x98badcfe;
+		tmp[3] = 0x10325476;
+#ifdef USE_SHA
+		tmp[4] = 0xc3d2e1f0;
+#endif
+		for (i = 0; i < POOLWORDS; i += 16)
+			HASH_TRANSFORM(tmp, r->pool+i);
+
+		/*
+		 * The following code does two separate things that happen
+		 * to both work two words at a time, so are convenient
+		 * to do together.
+		 *
+		 * First, this feeds the output back into the pool so
+		 * that the next call will return different results.
+		 * Any perturbation of the pool's state would do, even
+		 * changing one bit, but this mixes the pool nicely.
+		 *
+		 * Second, this folds the output in half to hide the data
+		 * fed back into the pool from the user and further mask
+		 * any patterns in the hash output.  (The exact folding
+		 * pattern is not important; the one used here is quick.)
+		 */
+		for (i = 0; i <  HASH_BUFFER_SIZE/2; i++) {
+			x = tmp[i + (HASH_BUFFER_SIZE+1)/2];
+			add_entropy_words(r, tmp[i], x);
+			tmp[i] ^= x;
+		}
+#if HASH_BUFFER_SIZE & 1	/* There's a middle word to deal with */
+		x = tmp[HASH_BUFFER_SIZE/2];
+		add_entropy_words(r, x, (__u32)((unsigned long)buf));
+		x ^= (x >> 16);		/* Fold it in half */
+		((__u16 *)tmp)[HASH_BUFFER_SIZE-1] = (__u16)x;
+#endif
+		
+		/* Copy data to destination buffer */
+		i = MIN(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2);
+		if (to_user) {
+			i -= copy_to_user(buf, (__u8 const *)tmp, i);
+			if (!i) {
+				ret = -EFAULT;
+				break;
+			}
+		} else
+			memcpy(buf, (__u8 const *)tmp, i);
+		nbytes -= i;
+		buf += i;
+		add_timer_randomness(r, &extract_timer_state, nbytes);
+		if (to_user && current->need_resched)
+		{
+			if (signal_pending(current))
+			{
+				ret = -EINTR;
+				break;
+			}
+#ifndef OSKIT
+			   schedule();
+#endif
+		}
+	}
+
+	/* Wipe data just returned from memory */
+	memset(tmp, 0, sizeof(tmp));
+	
+	return ret;
+}
+
+/*
+ * This function is the exported kernel interface.  It returns some
+ * number of good random numbers, suitable for seeding TCP sequence
+ * numbers, etc.
+ */
+void get_random_bytes(void *buf, int nbytes)
+{
+	extract_entropy(&random_state, (char *) buf, nbytes, 0);
+}
+
+FROBLINKAGE ssize_t
+random_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
+{
+	struct wait_queue 	wait = { current, NULL };
+	ssize_t			n, retval = 0, count = 0;
+	
+	if (nbytes == 0)
+		return 0;
+
+	add_wait_queue(&random_read_wait, &wait);
+	while (nbytes > 0) {
+		current->state = TASK_INTERRUPTIBLE;
+		n = nbytes;
+		if (n > random_state.entropy_count / 8)
+			n = random_state.entropy_count / 8;
+		if (n == 0) {
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				retval = -ERESTARTSYS;
+				break;
+			}
+#ifndef OSKIT
+			schedule();
+#endif
+			continue;
+		}
+		n = extract_entropy(&random_state, buf, n, 1);
+		if (n < 0) {
+			retval = n;
+			break;
+		}
+		count += n;
+		buf += n;
+		nbytes -= n;
+		break;		/* This break makes the device work */
+				/* like a named pipe */
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&random_read_wait, &wait);
+
+	/*
+	 * If we gave the user some bytes, update the access time.
+	 */
+	if (count != 0) {
+		UPDATE_ATIME(file->f_dentry->d_inode);
+	}
+	
+	return (count ? count : retval);
+}
+
+FROBLINKAGE ssize_t
+random_read_unlimited(struct file * file, char * buf,
+		      size_t nbytes, loff_t *ppos)
+{
+	return extract_entropy(&random_state, buf, nbytes, 1);
+}
+
+static unsigned int
+random_poll(struct file *file, poll_table * wait)
+{
+	unsigned int mask;
+
+#if 0 /* DLD */
+	poll_wait(file, &random_read_wait, wait);
+	poll_wait(file, &random_write_wait, wait);
+#endif
+	mask = 0;
+	if (random_state.entropy_count >= WAIT_INPUT_BITS)
+		mask |= POLLIN | POLLRDNORM;
+	if (random_state.entropy_count < WAIT_OUTPUT_BITS)
+		mask |= POLLOUT | POLLWRNORM;
+	return mask;
+}
+
+FROBLINKAGE ssize_t
+random_write(struct file * file, const char * buffer,
+	     size_t count, loff_t *ppos)
+{
+	int		ret = 0;
+	size_t		bytes;
+	unsigned	i;
+	__u32 		buf[16];
+	const char 	*p = buffer;
+	size_t		c = count;
+
+	while (c > 0) {
+		bytes = MIN(c, sizeof(buf));
+
+		bytes -= copy_from_user(&buf, p, bytes);
+		if (!bytes) {
+			ret = -EFAULT;
+			break;
+		}
+		c -= bytes;
+		p += bytes;
+		
+		i = (unsigned)((bytes-1) / (2 * sizeof(__u32)));
+		do {
+			add_entropy_words(&random_state, buf[2*i], buf[2*i+1]);
+		} while (i--);
+	}
+	if (p == buffer) {
+		return (ssize_t)ret;
+	} else {
+	    /* FIXME: DLD FIX THIS!!
+	    file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+	    mark_inode_dirty(file->f_dentry->d_inode);*/
+		return (ssize_t)(p - buffer);
+	}
+}
+
+FROBLINKAGE int
+random_ioctl(struct inode * inode, struct file * file,
+	     unsigned int cmd, unsigned long arg)
+{
+	int *p, size, ent_count;
+	int retval;
+	
+	switch (cmd) {
+	case RNDGETENTCNT:
+		ent_count = random_state.entropy_count;
+		if (put_user(ent_count, (int *) arg))
+			return -EFAULT;
+		return 0;
+	case RNDADDTOENTCNT:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (get_user(ent_count, (int *) arg))
+			return -EFAULT;
+		/*
+		 * Add i to entropy_count, limiting the result to be
+		 * between 0 and POOLBITS.
+		 */
+
+		/* +++ DLD */
+#if 0
+		printf("ent_count is %d\n", ent_count);
+		printf("random_state.entropy_count is %d\n", random_state.entropy_count);
+		printf("-random_state.entropy_count is %d\n", -random_state.entropy_count);
+		printf("POOLBITS is %d\n", POOLBITS);
+#endif
+		/* --- DLD */
+		if (ent_count < /*+++ DLD. */ 1
+				  /* Was:  -random_state.entropy_count*/
+		    /* I dont get this.  random_state.entropy_count is unsigned and
+		       negating it ends up as a large positive number.
+		       --- DLD. */
+		    )
+			random_state.entropy_count = 0;
+		else if (ent_count > POOLBITS)
+			random_state.entropy_count = POOLBITS;
+		else {
+			random_state.entropy_count += ent_count;
+			if (random_state.entropy_count > POOLBITS)
+				random_state.entropy_count = POOLBITS;
+			if (random_state.entropy_count < 0)
+				random_state.entropy_count = 0;
+		}
+
+		/*
+		 * Wake up waiting processes if we have enough
+		 * entropy.
+		 */
+		if (random_state.entropy_count >= WAIT_INPUT_BITS)
+			wake_up_interruptible(&random_read_wait);
+		return 0;
+	case RNDGETPOOL:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		p = (int *) arg;
+		ent_count = random_state.entropy_count;
+		if (put_user(ent_count, p++))
+			return -EFAULT;
+			
+		if (get_user(size, p))
+			return -EFAULT;
+		if (put_user(POOLWORDS, p++))
+			return -EFAULT;
+		if (size < 0)
+			return -EINVAL;
+		if (size > POOLWORDS)
+			size = POOLWORDS;
+		if (copy_to_user(p, random_state.pool, size*sizeof(__u32)))
+			return -EFAULT;
+		return 0;
+	case RNDADDENTROPY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		p = (int *) arg;
+		if (get_user(ent_count, p++))
+			return -EFAULT;
+		if (ent_count < 0)
+			return -EINVAL;
+		if (get_user(size, p++))
+			return -EFAULT;
+		retval = random_write(file, (const char *)p, size, &file->f_pos);
+
+		if (retval < 0)
+			return retval;
+		/*
+		 * Add ent_count to entropy_count, limiting the result to be
+		 * between 0 and POOLBITS.
+		 */
+		if (ent_count > POOLBITS)
+			random_state.entropy_count = POOLBITS;
+		else {
+			random_state.entropy_count += ent_count;
+			if (random_state.entropy_count > POOLBITS)
+				random_state.entropy_count = POOLBITS;
+			if (random_state.entropy_count < 0)
+				random_state.entropy_count = 0;
+		}
+		/*
+		 * Wake up waiting processes if we have enough
+		 * entropy.
+		 */
+		if (random_state.entropy_count >= WAIT_INPUT_BITS)
+			wake_up_interruptible(&random_read_wait);
+		return 0;
+#if 0
+	case RNDZAPENTCNT:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		random_state.entropy_count = 0;
+		return 0;
+	case RNDCLEARPOOL:
+		/* Clear the entropy pool and associated counters. */
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		rand_clear_pool();
+		return 0;
+#endif
+	default:
+		return -EINVAL;
+	}
+}
+
+struct file_operations random_fops = {
+	NULL,		/* random_lseek */
+	random_read,
+	random_write,
+	NULL,		/* random_readdir */
+	random_poll,	/* random_poll */
+	random_ioctl,
+	NULL,		/* random_mmap */
+	NULL,		/* no special open code */
+	NULL,		/* flush */
+	NULL		/* no special release code */
+};
+
+struct file_operations urandom_fops = {
+	NULL,		/* unrandom_lseek */
+	random_read_unlimited,
+	random_write,
+	NULL,		/* urandom_readdir */
+	NULL,		/* urandom_poll */
+	random_ioctl,
+	NULL,		/* urandom_mmap */
+	NULL,		/* no special open code */
+	NULL,		/* flush */
+	NULL		/* no special release code */
+};
+
+/*
+ * TCP initial sequence number picking.  This uses the random number
+ * generator to pick an initial secret value.  This value is hashed
+ * along with the TCP endpoint information to provide a unique
+ * starting point for each pair of TCP endpoints.  This defeats
+ * attacks which rely on guessing the initial TCP sequence number.
+ * This algorithm was suggested by Steve Bellovin.
+ *
+ * Using a very strong hash was taking an appreciable amount of the total
+ * TCP connection establishment time, so this is a weaker hash,
+ * compensated for by changing the secret periodically.
+ */
+
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/*
+ * The generic round function.  The application is so specific that
+ * we don't bother protecting all the arguments with parens, as is generally
+ * good macro practice, in favor of extra legibility.
+ * Rotation is separate from addition to prevent recomputation
+ */
+#define ROUND(f, a, b, c, d, x, s)	\
+	(a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
+#define K1 0
+#define K2 013240474631UL
+#define K3 015666365641UL
+
+/*
+ * Basic cut-down MD4 transform.  Returns only 32 bits of result.
+ */
+static __u32 halfMD4Transform (__u32 const buf[4], __u32 const in[8])
+{
+	__u32	a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+	/* Round 1 */
+	ROUND(F, a, b, c, d, in[0] + K1,  3);
+	ROUND(F, d, a, b, c, in[1] + K1,  7);
+	ROUND(F, c, d, a, b, in[2] + K1, 11);
+	ROUND(F, b, c, d, a, in[3] + K1, 19);
+	ROUND(F, a, b, c, d, in[4] + K1,  3);
+	ROUND(F, d, a, b, c, in[5] + K1,  7);
+	ROUND(F, c, d, a, b, in[6] + K1, 11);
+	ROUND(F, b, c, d, a, in[7] + K1, 19);
+
+	/* Round 2 */
+	ROUND(G, a, b, c, d, in[1] + K2,  3);
+	ROUND(G, d, a, b, c, in[3] + K2,  5);
+	ROUND(G, c, d, a, b, in[5] + K2,  9);
+	ROUND(G, b, c, d, a, in[7] + K2, 13);
+	ROUND(G, a, b, c, d, in[0] + K2,  3);
+	ROUND(G, d, a, b, c, in[2] + K2,  5);
+	ROUND(G, c, d, a, b, in[4] + K2,  9);
+	ROUND(G, b, c, d, a, in[6] + K2, 13);
+
+	/* Round 3 */
+	ROUND(H, a, b, c, d, in[3] + K3,  3);
+	ROUND(H, d, a, b, c, in[7] + K3,  9);
+	ROUND(H, c, d, a, b, in[2] + K3, 11);
+	ROUND(H, b, c, d, a, in[6] + K3, 15);
+	ROUND(H, a, b, c, d, in[1] + K3,  3);
+	ROUND(H, d, a, b, c, in[5] + K3,  9);
+	ROUND(H, c, d, a, b, in[0] + K3, 11);
+	ROUND(H, b, c, d, a, in[4] + K3, 15);
+
+	return buf[1] + b;	/* "most hashed" word */
+	/* Alternative: return sum of all words? */
+}
+
+#if 0	/* May be needed for IPv6 */
+
+static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12])
+{
+	__u32	a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+	/* Round 1 */
+	ROUND(F, a, b, c, d, in[ 0] + K1,  3);
+	ROUND(F, d, a, b, c, in[ 1] + K1,  7);
+	ROUND(F, c, d, a, b, in[ 2] + K1, 11);
+	ROUND(F, b, c, d, a, in[ 3] + K1, 19);
+	ROUND(F, a, b, c, d, in[ 4] + K1,  3);
+	ROUND(F, d, a, b, c, in[ 5] + K1,  7);
+	ROUND(F, c, d, a, b, in[ 6] + K1, 11);
+	ROUND(F, b, c, d, a, in[ 7] + K1, 19);
+	ROUND(F, a, b, c, d, in[ 8] + K1,  3);
+	ROUND(F, d, a, b, c, in[ 9] + K1,  7);
+	ROUND(F, c, d, a, b, in[10] + K1, 11);
+	ROUND(F, b, c, d, a, in[11] + K1, 19);
+
+	/* Round 2 */
+	ROUND(G, a, b, c, d, in[ 1] + K2,  3);
+	ROUND(G, d, a, b, c, in[ 3] + K2,  5);
+	ROUND(G, c, d, a, b, in[ 5] + K2,  9);
+	ROUND(G, b, c, d, a, in[ 7] + K2, 13);
+	ROUND(G, a, b, c, d, in[ 9] + K2,  3);
+	ROUND(G, d, a, b, c, in[11] + K2,  5);
+	ROUND(G, c, d, a, b, in[ 0] + K2,  9);
+	ROUND(G, b, c, d, a, in[ 2] + K2, 13);
+	ROUND(G, a, b, c, d, in[ 4] + K2,  3);
+	ROUND(G, d, a, b, c, in[ 6] + K2,  5);
+	ROUND(G, c, d, a, b, in[ 8] + K2,  9);
+	ROUND(G, b, c, d, a, in[10] + K2, 13);
+
+	/* Round 3 */
+	ROUND(H, a, b, c, d, in[ 3] + K3,  3);
+	ROUND(H, d, a, b, c, in[ 7] + K3,  9);
+	ROUND(H, c, d, a, b, in[11] + K3, 11);
+	ROUND(H, b, c, d, a, in[ 2] + K3, 15);
+	ROUND(H, a, b, c, d, in[ 6] + K3,  3);
+	ROUND(H, d, a, b, c, in[10] + K3,  9);
+	ROUND(H, c, d, a, b, in[ 1] + K3, 11);
+	ROUND(H, b, c, d, a, in[ 5] + K3, 15);
+	ROUND(H, a, b, c, d, in[ 9] + K3,  3);
+	ROUND(H, d, a, b, c, in[ 0] + K3,  9);
+	ROUND(H, c, d, a, b, in[ 4] + K3, 11);
+	ROUND(H, b, c, d, a, in[ 8] + K3, 15);
+
+	return buf[1] + b;	/* "most hashed" word */
+	/* Alternative: return sum of all words? */
+}
+#endif
+
+#undef ROUND
+#undef F
+#undef G
+#undef H
+#undef K1
+#undef K2
+#undef K3
+
+/* This should not be decreased so low that ISNs wrap too fast. */
+#define REKEY_INTERVAL	300
+#define HASH_BITS 24
+
+__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
+				 __u16 sport, __u16 dport)
+{
+	static __u32	rekey_time = 0;
+	static __u32	count = 0;
+	static __u32	secret[12];
+	struct timeval 	tv;
+	__u32		seq;
+
+	/*
+	 * Pick a random secret every REKEY_INTERVAL seconds.
+	 */
+	do_gettimeofday(&tv);	/* We need the usecs below... */
+
+	if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
+		rekey_time = tv.tv_sec;
+		/* First three words are overwritten below. */
+		get_random_bytes(&secret+3, sizeof(secret)-12);
+		count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
+	}
+
+	/*
+	 *  Pick a unique starting offset for each TCP connection endpoints
+	 *  (saddr, daddr, sport, dport).
+	 *  Note that the words are placed into the first words to be
+	 *  mixed in with the halfMD4.  This is because the starting
+	 *  vector is also a random secret (at secret+8), and further
+	 *  hashing fixed data into it isn't going to improve anything,
+	 *  so we should get started with the variable data.
+	 */
+	secret[0]=saddr;
+	secret[1]=daddr;
+	secret[2]=(sport << 16) + dport;
+
+	seq = (halfMD4Transform(secret+8, secret) &
+	       ((1<<HASH_BITS)-1)) + count;
+
+	/*
+	 *	As close as possible to RFC 793, which
+	 *	suggests using a 250 kHz clock.
+	 *	Further reading shows this assumes 2 Mb/s networks.
+	 *	For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
+	 *	That's funny, Linux has one built in!  Use it!
+	 *	(Networks are faster now - should this be increased?)
+	 */
+	seq += tv.tv_usec + tv.tv_sec*1000000;
+#if 0
+	printk("init_seq(%lx, %lx, %d, %d) = %d\n",
+	       saddr, daddr, sport, dport, seq);
+#endif
+	return seq;
+}
+
+#ifdef CONFIG_SYN_COOKIES
+/*
+ * Secure SYN cookie computation. This is the algorithm worked out by
+ * Dan Bernstein and Eric Schenk.
+ *
+ * For linux I implement the 1 minute counter by looking at the jiffies clock.
+ * The count is passed in as a parameter, so this code doesn't much care.
+ */
+
+#define COOKIEBITS 24	/* Upper bits store count */
+#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
+
+static int	syncookie_init = 0;
+static __u32	syncookie_secret[2][16-3+HASH_BUFFER_SIZE];
+
+__u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport,
+		__u16 dport, __u32 sseq, __u32 count, __u32 data)
+{
+	__u32 	tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
+	__u32	seq;
+
+	/*
+	 * Pick two random secrets the first time we need a cookie.
+	 */
+	if (syncookie_init == 0) {
+		get_random_bytes(syncookie_secret, sizeof(syncookie_secret));
+		syncookie_init = 1;
+	}
+
+	/*
+	 * Compute the secure sequence number.
+	 * The output should be:
+   	 *   HASH(sec1,saddr,sport,daddr,dport,sec1) + sseq + (count * 2^24)
+	 *      + (HASH(sec2,saddr,sport,daddr,dport,count,sec2) % 2^24).
+	 * Where sseq is their sequence number and count increases every
+	 * minute by 1.
+	 * As an extra hack, we add a small "data" value that encodes the
+	 * MSS into the second hash value.
+	 */
+
+	memcpy(tmp+3, syncookie_secret[0], sizeof(syncookie_secret[0]));
+	tmp[0]=saddr;
+	tmp[1]=daddr;
+	tmp[2]=(sport << 16) + dport;
+	HASH_TRANSFORM(tmp+16, tmp);
+	seq = tmp[17] + sseq + (count << COOKIEBITS);
+
+	memcpy(tmp+3, syncookie_secret[1], sizeof(syncookie_secret[1]));
+	tmp[0]=saddr;
+	tmp[1]=daddr;
+	tmp[2]=(sport << 16) + dport;
+	tmp[3] = count;	/* minute counter */
+	HASH_TRANSFORM(tmp+16, tmp);
+
+	/* Add in the second hash and the data */
+	return seq + ((tmp[17] + data) & COOKIEMASK);
+}
+
+/*
+ * This retrieves the small "data" value from the syncookie.
+ * If the syncookie is bad, the data returned will be out of
+ * range.  This must be checked by the caller.
+ *
+ * The count value used to generate the cookie must be within
+ * "maxdiff" if the current (passed-in) "count".  The return value
+ * is (__u32)-1 if this test fails.
+ */
+__u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, __u16 sport,
+		__u16 dport, __u32 sseq, __u32 count, __u32 maxdiff)
+{
+	__u32 	tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
+	__u32	diff;
+
+	if (syncookie_init == 0)
+		return (__u32)-1;	/* Well, duh! */
+
+	/* Strip away the layers from the cookie */
+	memcpy(tmp+3, syncookie_secret[0], sizeof(syncookie_secret[0]));
+	tmp[0]=saddr;
+	tmp[1]=daddr;
+	tmp[2]=(sport << 16) + dport;
+	HASH_TRANSFORM(tmp+16, tmp);
+	cookie -= tmp[17] + sseq;
+	/* Cookie is now reduced to (count * 2^24) ^ (hash % 2^24) */
+
+	diff = (count - (cookie >> COOKIEBITS)) & ((__u32)-1 >> COOKIEBITS);
+	if (diff >= maxdiff)
+		return (__u32)-1;
+
+	memcpy(tmp+3, syncookie_secret[1], sizeof(syncookie_secret[1]));
+	tmp[0] = saddr;
+	tmp[1] = daddr;
+	tmp[2] = (sport << 16) + dport;
+	tmp[3] = count - diff;	/* minute counter */
+	HASH_TRANSFORM(tmp+16, tmp);
+
+	return (cookie - tmp[17]) & COOKIEMASK;	/* Leaving the data behind */
+}
+#endif
+
+
+#ifdef RANDOM_BENCHMARK
+/*
+ * This is so we can do some benchmarking of the random driver, to see
+ * how much overhead add_timer_randomness really takes.  This only
+ * works on a Pentium, since it depends on the timer clock...
+ *
+ * Note: the results of this benchmark as of this writing (5/27/96)
+ *
+ * On a Pentium, add_timer_randomness() takes between 150 and 1000
+ * clock cycles, with an average of around 600 clock cycles.  On a 75
+ * MHz Pentium, this translates to 2 to 13 microseconds, with an
+ * average time of 8 microseconds.  This should be fast enough so we
+ * can use add_timer_randomness() even with the fastest of interrupts...
+ */
+static inline unsigned long long get_clock_cnt(void)
+{
+	unsigned long low, high;
+	__asm__(".byte 0x0f,0x31" :"=a" (low), "=d" (high));
+	return (((unsigned long long) high << 32) | low); 
+}
+
+__initfunc(static void
+initialize_benchmark(struct random_benchmark *bench,
+	             const char *descr, int unit))
+{
+	bench->times = 0;
+	bench->accum = 0;
+	bench->max = 0;
+	bench->min = 1 << 31;
+	bench->descr = descr;
+	bench->unit = unit;
+}
+
+static void begin_benchmark(struct random_benchmark *bench)
+{
+#ifdef BENCHMARK_NOINT
+	save_flags(bench->flags); cli();
+#endif
+	bench->start_time = get_clock_cnt();
+}
+
+static void end_benchmark(struct random_benchmark *bench)
+{
+	unsigned long ticks;
+	
+	ticks = (unsigned long) (get_clock_cnt() - bench->start_time);
+#ifdef BENCHMARK_NOINT
+	restore_flags(bench->flags);
+#endif
+	if (ticks < bench->min)
+		bench->min = ticks;
+	if (ticks > bench->max)
+		bench->max = ticks;
+	bench->accum += ticks;
+	bench->times++;
+	if (bench->times == BENCHMARK_INTERVAL) {
+		printk("Random benchmark: %s %d: %lu min, %lu avg, "
+		       "%lu max\n", bench->descr, bench->unit, bench->min,
+		       bench->accum / BENCHMARK_INTERVAL, bench->max);
+		bench->times = 0;
+		bench->accum = 0;
+		bench->max = 0;
+		bench->min = 1 << 31;
+	}
+}	
+#endif /* RANDOM_BENCHMARK */
diff -ruN oskit-20020317/linux/src/drivers/net/ne.c oskit-20020317-entropy/linux/src/drivers/net/ne.c
--- oskit-20020317/linux/src/drivers/net/ne.c	Wed Nov 10 19:53:24 1999
+++ oskit-20020317-entropy/linux/src/drivers/net/ne.c	Thu Jan  2 11:04:43 2003
@@ -457,7 +457,9 @@
 
 	{
 		int irqval = request_irq(dev->irq, ei_interrupt,
-				 pci_irq_line ? SA_SHIRQ : 0, name, dev);
+				 pci_irq_line ?
+					 SA_SHIRQ | SA_SAMPLE_RANDOM :
+					 SA_SAMPLE_RANDOM, name, dev);
 		if (irqval) {
 			printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
 			kfree(dev->priv);
diff -ruN oskit-20020317/linux/src/include/asm-i386/processor.h oskit-20020317-entropy/linux/src/include/asm-i386/processor.h
--- oskit-20020317/linux/src/include/asm-i386/processor.h	Fri Dec  3 13:21:19 1999
+++ oskit-20020317-entropy/linux/src/include/asm-i386/processor.h	Thu Jan  2 11:04:43 2003
@@ -29,7 +29,18 @@
 	char	hard_math;
 	char	rfu;
 	int	cpuid_level;	/* Maximum supported CPUID level, -1=no CPUID */
-	__u32	x86_capability;
+#else
+    __u8 resv0;
+    __u8 resv1;
+    __u8 resv2;
+    char resv3;
+    char resv4;
+    char resv5;
+    char resv6;
+    int resv7;
+#endif
+    __u32	x86_capability; /* DLD: needed for random.c */
+#ifndef OSKIT
 	char	x86_vendor_id[16];
 	char	x86_model_id[64];
 	int 	x86_cache_size;  /* in KB - valid for CPUS which support this
diff -ruN oskit-20020317/linux/src/include/linux/random.h oskit-20020317-entropy/linux/src/include/linux/random.h
--- oskit-20020317/linux/src/include/linux/random.h	Wed Nov 10 19:54:56 1999
+++ oskit-20020317-entropy/linux/src/include/linux/random.h	Thu Jan  2 11:10:46 2003
@@ -35,7 +35,11 @@
 struct rand_pool_info {
 	int	entropy_count;
 	int	buf_size;
+#ifndef OSKIT
 	__u32	buf[0];
+#else
+	oskit_u32_t buf[0];
+#endif
 };
 
 /* Exported functions */
diff -ruN oskit-20020317/linux/src/include/linux/sched.h oskit-20020317-entropy/linux/src/include/linux/sched.h
--- oskit-20020317/linux/src/include/linux/sched.h	Mon Feb 19 22:24:10 2001
+++ oskit-20020317-entropy/linux/src/include/linux/sched.h	Thu Jan  2 11:04:43 2003
@@ -271,6 +271,7 @@
 	mm_segment_t addr_limit;
 #ifdef OSKIT_FS
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
+	long need_resched; /* Used by random.c */
 	long counter;
 	int groups[NGROUPS];
 	unsigned short uid /* fsuid below */;
diff -ruN oskit-20020317/modules.x86.pc oskit-20020317-entropy/modules.x86.pc
--- oskit-20020317/modules.x86.pc	Tue Mar 12 12:38:48 2002
+++ oskit-20020317-entropy/modules.x86.pc	Thu Jan  2 11:04:43 2003
@@ -202,6 +202,9 @@
 ## Requires the udp library.
 #netdisk
 
+### The Linux random number device.
+random
+
 ### --- Scripts and build/debug utilities
 
 ### Includes the CPU-oskit-gcc wrapper.
diff -ruN oskit-20020317/oskit/dev/GUID oskit-20020317-entropy/oskit/dev/GUID
--- oskit-20020317/oskit/dev/GUID	Tue Feb 27 15:28:36 2001
+++ oskit-20020317-entropy/oskit/dev/GUID	Thu Jan  2 11:04:43 2003
@@ -110,3 +110,6 @@
 4aa7e007-7c74-11cf-b500-08000953adc2	oskit_mib_egp
 4aa7e008-7c74-11cf-b500-08000953adc2	oskit_mib_dot3
 4aa7e009-7c74-11cf-b500-08000953adc2	oskit_mib_snmp
+
+4aa7e00a-7c74-11cf-b500-08000953adc2	oskit_entropy
+4aa7e00b-7c74-11cf-b500-08000953adc2	oskit_entropychannel
diff -ruN oskit-20020317/oskit/dev/entropy.h oskit-20020317-entropy/oskit/dev/entropy.h
--- oskit-20020317/oskit/dev/entropy.h	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/oskit/dev/entropy.h	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,91 @@
+/*
+ * Entropy Pool Interface.
+ *
+ * Copyright (c) 2002, 2003 Derek L Davies (ddavies@ddavies.net)
+ *
+ */
+
+#ifndef _OSKIT_DEV_ENTROPY_H_
+#define _OSKIT_DEV_ENTROPY_H_
+
+#include <oskit/dev/device.h>
+#include <oskit/com/stream.h>
+#include <oskit/io/asyncio.h>
+#include <oskit/dev/entropy_channel.h>
+
+struct oskit_entropy {
+	struct oskit_entropy_ops *ops;
+};
+typedef struct oskit_entropy oskit_entropy_t;
+
+struct oskit_entropy_ops {
+
+	/*** COM-specified IUnknown interface operations ***/
+	OSKIT_COMDECL_IUNKNOWN(oskit_entropy_t)
+
+	/*** For both oskit_device_t and oskit_driver_t.  device needs
+	     just getinfo, and driver needs both getinfo and getdriver. ***/
+	OSKIT_COMDECL	(*getinfo)(oskit_entropy_t *r,
+				   oskit_devinfo_t *out_info);
+	OSKIT_COMDECL	(*getdriver)(oskit_entropy_t *r,
+				     oskit_driver_t **out_driver);
+
+	OSKIT_COMDECL (*getstats)(oskit_entropy_t *e,
+				  oskit_entropy_stats_t *out_stats);
+
+	/*** This is how device drivers attach to the entropy driver(s).
+	     They add entropy via the entropy channel. ***/
+	OSKIT_COMDECL (*attach_source)(oskit_entropy_t *e,
+				       char *name,
+				       oskit_u32_t type,
+				       oskit_u32_t flags,
+				       oskit_entropy_channel_t **out_chan);
+
+	/*** This is an interface for non blocking, read only, calls.
+	     It roughly corresponds to /dev/urandom . ***/
+	OSKIT_COMDECL (*open_nonblocking)(oskit_entropy_t *e,
+					  oskit_stream_t **out_stream_obj);
+
+	/*** This is an interface for extracting good randomness and, as such,
+	     it may block.  Entropy is both readable and writeable via this
+	     interface.  It roughly corresponds to /dev/random . ***/
+	OSKIT_COMDECL (*open_good)(oskit_entropy_t *e,
+				   oskit_stream_t **out_stream_obj,
+				   oskit_asyncio_t **out_async_obj);
+};
+
+/* GUID for oskit_entropy interface */
+extern const struct oskit_guid oskit_entropy_iid;
+#define OSKIT_ENTROPY_IID OSKIT_GUID(0x4aa7e00a, 0x7c74, 0x11cf, \
+				     0xb5, 0x00, 0x08, 0x00, \
+                                     0x09, 0x53, 0xad, 0xc2)
+
+#define oskit_entropy_query(e, iid, out_ihandle) \
+	((e)->ops->query((oskit_entropy_t *)(e), (iid), (out_ihandle)))
+#define oskit_entropy_addref(e) \
+	((e)->ops->addref((oskit_entropy_t *)(e)))
+#define oskit_entropy_release(e) \
+	((e)->ops->release((oskit_entropy_t *)(e)))
+
+#define oskit_entropy_getinfo(e, inf) \
+	((e)->ops->getinfo((oskit_entropy_t *)(e), (inf)))
+#define oskit_entropy_getdriver(e, dev, drv) \
+	((e)->ops->getdriver((oskit_entropy_t *)(e), (dev), (drv)))
+
+#define oskit_entropy_getstats(e, stats) \
+	((e)->ops->getstats((oskit_entropy_t *)(e), (stats)))
+#define oskit_entropy_attach_source(e, name, type, flags, chan) \
+	((e)->ops->attach_source((oskit_entropy_t *)(e), \
+				 (name), (type), (flags), (chan)))
+#define oskit_entropy_open_nonblocking(e, stream) \
+	((e)->ops->open_nonblocking((oskit_entropy_t *)(e), (stream)))
+#define oskit_entropy_open_good(e, stream, asyncio) \
+	((e)->ops->open_good((oskit_entropy_t *)(e), (stream), (asyncio)))
+#define oskit_entropy_add_data(e, data, len, entropy) \
+	((e)->ops->add_data((oskit_entropy_t *)(e), (data), (len), (entropy)))
+
+oskit_error_t create_entropy_channel(oskit_osenv_mem_t *mem,
+				     oskit_entropy_t *ep,
+				     oskit_entropy_channel_t **out_chan);
+
+#endif /* _OSKIT_DEV_ENTROPY_H_ */
diff -ruN oskit-20020317/oskit/dev/entropy_channel.h oskit-20020317-entropy/oskit/dev/entropy_channel.h
--- oskit-20020317/oskit/dev/entropy_channel.h	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/oskit/dev/entropy_channel.h	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,56 @@
+#ifndef _OSKIT_DEV_ENTROPY_CHANNEL_H_
+#define _OSKIT_DEV_ENTROPY_CHANNEL_H_
+
+#include <oskit/com.h>
+#include <oskit/error.h>
+#include <oskit/dev/osenv_mem.h>
+#include <oskit/dev/entropy_stats.h>
+
+/*
+ * Entropy channel interface.  This is how drivers
+ * add entropy to the entropy device(s).
+ *
+ * IID: 4aa7e00b-7c74-11cf-b500-08000953adc2
+ *
+ * Copyright (c) 2002, 2003 Derek L Davies (ddavies@ddavies.net)
+ *
+ */
+struct oskit_entropy_channel {
+    struct oskit_entropy_channel_ops *ops;
+};
+typedef struct oskit_entropy_channel oskit_entropy_channel_t;
+
+struct oskit_entropy_channel_ops {
+
+    /*** COM-specified IUnknown interface operations ***/
+    OSKIT_COMDECL_IUNKNOWN(oskit_entropy_channel_t);
+
+    /*** Entropy channel stuff ***/
+    OSKIT_COMDECL_V (*add_data)(oskit_entropy_channel_t *c, void *data,
+				oskit_u32_t len, oskit_u32_t entropy);
+
+    OSKIT_COMDECL_V (*get_stats)(oskit_entropy_channel_t *c,
+				 oskit_entropy_stats_t *stats);
+};
+
+/* GUID for oskit_entropy_channel interface */
+extern const struct oskit_guid oskit_entropy_channel_iid;
+#define OSKIT_ENTROPY_CHANNEL_IID OSKIT_GUID(0x4aa7e00b, 0x7c74, 0x11cf, \
+				             0xb5, 0x00, 0x08, 0x00, \
+                                             0x09, 0x53, 0xad, 0xc2)
+
+#define oskit_entropy_channel_query(c, iid, out_ihandle) \
+	((c)->ops->query((oskit_entropy_channel_t *)(c), (iid), (out_ihandle)))
+#define oskit_entropy_channel_addref(c) \
+	((c)->ops->addref((oskit_entropy_channel_t *)(c)))
+#define oskit_entropy_channel_release(c) \
+	((c)->ops->release((oskit_entropy_channel_t *)(c)))
+
+#define oskit_entropy_channel_add_data(c, data, len, entropy) \
+	((c)->ops->add_data((oskit_entropy_channel_t *)(c), (data), (len), \
+			    (entropy)))
+
+#define oskit_entropy_channel_get_stats(c, stats) \
+	((c)->ops->get_stats((oskit_entropy_channel_t *)(c), (stats)))
+
+#endif /* _OSKIT_DEV_ENTROPY_CHANNEL_H_ */
diff -ruN oskit-20020317/oskit/dev/entropy_stats.h oskit-20020317-entropy/oskit/dev/entropy_stats.h
--- oskit-20020317/oskit/dev/entropy_stats.h	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/oskit/dev/entropy_stats.h	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,14 @@
+#ifndef _OSKIT_DEV_ENTROPY_STATS_H_
+#define _OSKIT_DEV_ENTROPY_STATS_H_
+
+struct oskit_entropy_stats {
+    
+    /* Number of calls to entropy_getstats. */
+    unsigned int n_calls;
+
+    /* Estimate of the amount entropy in the pool. */
+    unsigned int entropy_count;
+};
+typedef struct oskit_entropy_stats oskit_entropy_stats_t;
+
+#endif /* _OSKIT_DEV_ENTROPY_STATS_H_ */
diff -ruN oskit-20020317/oskit/dev/linux.h oskit-20020317-entropy/oskit/dev/linux.h
--- oskit-20020317/oskit/dev/linux.h	Mon Feb 19 23:50:24 2001
+++ oskit-20020317-entropy/oskit/dev/linux.h	Thu Jan  2 11:11:28 2003
@@ -60,6 +60,8 @@
 void oskit_linux_init_blk(void);
 void oskit_linux_init_net(void);
 
+/* Initialize one or more entropy devices */
+void oskit_linux_init_entropy(void);
 
 /*** Functions to initialize and register individual device drivers ***/
 /*
@@ -71,6 +73,7 @@
 /* Special drivers handled individually */
 oskit_error_t oskit_linux_init_ide(void);
 oskit_error_t oskit_linux_init_floppy(void);
+oskit_error_t oskit_linux_init_randompool(void);
 
 /* SCSI device drivers */
 #define driver(name, description, vendor, author, filename, template) \
@@ -84,6 +87,7 @@
 #include <oskit/dev/linux_ethernet.h>
 #undef driver
 
+oskit_error_t oskit_linux_init_randompools_randompool(void);
 
 /*** Back-door interfaces ***/
 /*
diff -ruN oskit-20020317/oskit/dev/linux_entropy.h oskit-20020317-entropy/oskit/dev/linux_entropy.h
--- oskit-20020317/oskit/dev/linux_entropy.h	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/oskit/dev/linux_entropy.h	Thu Jan  2 11:04:43 2003
@@ -0,0 +1,10 @@
+
+/* entropy(<name>, <description>, <vendor>, <author>, <filename>, <initfxn>)
+*/
+entropy(random, "Blocking (good entropy)", "Linux 2.2.12", "Theodore Ts-o", "random", rand_initialize)
+
+/* You can get multiple entropy pools by including more entropy lines.
+   This doesn't seem to make much sense though.
+*/
+    
+/* End of linux_entropy.h */
diff -ruN oskit-20020317/startup/GNUmakerules oskit-20020317-entropy/startup/GNUmakerules
--- oskit-20020317/startup/GNUmakerules	Tue May  8 13:26:13 2001
+++ oskit-20020317-entropy/startup/GNUmakerules	Thu Jan  2 11:04:44 2003
@@ -31,7 +31,7 @@
 		start_fs_bmod_pthreads.o start_world_pthreads.o \
 		start_bmod_pthreads.o start_network_router_pthreads.o \
 		start_conf_network_pthreads.o start_linux_fs_pthreads.o \
-		start_network_single_pthreads.o
+		start_network_single_pthreads.o start_entropy_devices.o
 
 include $(OSKIT_SRCDIR)/GNUmakerules-lib
 
diff -ruN oskit-20020317/startup/start_devices.c oskit-20020317-entropy/startup/start_devices.c
--- oskit-20020317/startup/start_devices.c	Thu Nov  2 17:21:16 2000
+++ oskit-20020317-entropy/startup/start_devices.c	Thu Jan  2 11:04:44 2003
@@ -46,6 +46,7 @@
  */
 void (*_init_devices_blk)();
 void (*_init_devices_net)();
+void (*_init_devices_entropy)();
 
 void
 start_devices(void)
@@ -63,8 +64,12 @@
 	oskit_dev_init(osenv);
 	oskit_linux_init_osenv(osenv);
 
+	if (_init_devices_entropy)
+                (*_init_devices_entropy)();
+	
 	if (_init_devices_blk)
 		(*_init_devices_blk)();
+
 	if (_init_devices_net)
 		(*_init_devices_net)();
 
diff -ruN oskit-20020317/startup/start_entropy_devices.c oskit-20020317-entropy/startup/start_entropy_devices.c
--- oskit-20020317/startup/start_entropy_devices.c	Wed Dec 31 19:00:00 1969
+++ oskit-20020317-entropy/startup/start_entropy_devices.c	Thu Jan  2 11:04:44 2003
@@ -0,0 +1,39 @@
+
+/*
+ * start_entropy_devices.c
+ */
+
+#include <oskit/startup.h>
+#include <oskit/dev/linux.h>
+
+void
+start_entropy_devices(void)
+{
+	start_devices();
+}
+
+/*
+ * Having this initialization here makes `start_devices' (start_devices.c)
+ * initialize the random pool drivers, since linking in this file means
+ * the program is using the entropy store(s).
+ */
+
+#ifdef HAVE_CONSTRUCTOR
+/*
+ * Place initilization in the init section to be called at startup
+ */
+static void initme(void) __attribute__ ((constructor));
+
+static void
+initme(void)
+{
+	extern void (*_init_devices_entropy)(void);
+	printf("setting _init_devices_entropy\n");
+	_init_devices_entropy = oskit_linux_init_entropy;
+}
+#else
+/*
+ * Use a (dreaded) common symbol
+ */
+void (*_init_devices_entropy)(void) = oskit_linux_init_entropy;
+#endif
