diff -ruN oskit-20020317/examples/x86/GNUmakerules oskit-20020317-entropy/examples/x86/GNUmakerules --- oskit-20020317/examples/x86/GNUmakerules 2003-01-06 15:59:08.000000000 -0500 +++ oskit-20020317-entropy/examples/x86/GNUmakerules 2003-01-14 09:15:55.000000000 -0500 @@ -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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/examples/x86/entropy/rndtest.c 2003-01-16 13:07:40.000000000 -0500 @@ -0,0 +1,552 @@ + +/* + * Entropy pool test kernel. The code that runs the network and disk was + * snarfed from other example kernels. + */ + +#include /* smemalign */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 oskit_error_t (*_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***)ðerdev_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(ð->ether_shost, ð->ether_dhost, + sizeof(dev->haddr)); + bcopy(&dev->haddr, ð->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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/examples/x86/entropy/rndunittest.c 2003-01-16 13:09:24.000000000 -0500 @@ -0,0 +1,428 @@ + +/* + * Entropy device unit tests. + */ + +#include /* smemalign */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern oskit_error_t (*_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((void*)(entropy_aref[i]) == (void*)iunknown); + + oskit_iunknown_query(iunknown, + &oskit_entropy_iid, + (void**)&ent); + osenv_log(OSENV_LOG_INFO, + "DLD: entropy from iunknown is %p\n", ent); + assert((void*)iunknown == (void*)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((void*)(entropy_aref[i]) == (void*)device); + + oskit_device_query(device, + &oskit_entropy_iid, + (void**)&ent); + osenv_log(OSENV_LOG_INFO, + "DLD: entropy from device is %p\n", ent); + assert((void*)device == (void*)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((void*)(entropy_aref[i]) == (void*)driver); + + oskit_driver_query(driver, + &oskit_entropy_iid, + (void**)&ent); + osenv_log(OSENV_LOG_INFO, + "DLD: entropy from driver is %p\n", ent); + assert((void*)driver == (void*)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 2003-01-06 18:07:59.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/GNUmakerules 2003-01-14 09:15:55.000000000 -0500 @@ -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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/entropy.c 2003-01-14 20:01:24.000000000 -0500 @@ -0,0 +1,877 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "glue.h" +#include "entropy.h" +#include "entropy_driver.h" +#include "entropy_impl.h" +#include + +/* + Copyright (c) 2002, 2003 Derek L Davies (ddavies@ddavies.net) +*/ + +/*#if LINUX_RANDOM_DEVICE*/ +#include +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, (unsigned long)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, (unsigned long)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] = (oskit_u32_t)data; + random_ioctl(NULL, &(ei->fs), RNDADDENTROPY, (unsigned long)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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/entropy.h 2003-01-14 09:15:55.000000000 -0500 @@ -0,0 +1,32 @@ + +#ifndef _LINUX_DEV_ENTROPY_H_ +#define _LINUX_DEV_ENTROPY_H_ + +#include +#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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/entropy_channel.c 2003-01-14 09:15:55.000000000 -0500 @@ -0,0 +1,111 @@ +#include +#include +#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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/entropy_driver.h 2003-01-14 09:15:55.000000000 -0500 @@ -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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/entropy_impl.h 2003-01-14 09:15:55.000000000 -0500 @@ -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 +#include +#include +#include +#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 2003-01-06 16:05:24.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/global.h 2003-01-14 09:15:55.000000000 -0500 @@ -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 2003-01-06 16:05:25.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/init_all.c 2003-01-16 14:00:06.000000000 -0500 @@ -21,4 +21,5 @@ { oskit_linux_init_blk(); oskit_linux_init_net(); + (void)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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/init_entropy.c 2003-01-16 13:11:49.000000000 -0500 @@ -0,0 +1,12 @@ + +#include + +#include "glue.h" + +oskit_error_t oskit_linux_init_entropy(void) +{ +#define entropy(name, description, vendor, author, filename, probe) \ + INIT_DRIVER(entropy_##name, description " Entropy driver"); +#include + return 0; +} diff -ruN oskit-20020317/linux/dev/irq.c oskit-20020317-entropy/linux/dev/irq.c --- oskit-20020317/linux/dev/irq.c 2003-01-06 16:05:25.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/irq.c 2003-01-16 13:16:18.000000000 -0500 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "irq.h" @@ -112,6 +113,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 2003-01-06 16:05:25.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/misc.c 2003-01-14 09:15:55.000000000 -0500 @@ -27,6 +27,7 @@ #include #include #include +#include #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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/linux/dev/randompool.h 2003-01-14 09:15:55.000000000 -0500 @@ -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 2003-01-06 16:05:29.000000000 -0500 +++ oskit-20020317-entropy/linux/shared/s_init.c 2003-01-14 09:15:55.000000000 -0500 @@ -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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/linux/src/drivers/char/random.c 2003-01-16 14:07:32.000000000 -0500 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* DLD: Might be a linux bug. Need for CURRENT_TIME macro. */ +#include /* DLD: Might be a linux bug. Need for struct new_utsname . */ + +#include +#include +#include +#include + +#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<>(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<> 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 2003-01-06 16:06:04.000000000 -0500 +++ oskit-20020317-entropy/linux/src/drivers/net/ne.c 2003-01-14 09:15:55.000000000 -0500 @@ -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 2003-01-06 16:07:52.000000000 -0500 +++ oskit-20020317-entropy/linux/src/include/asm-i386/processor.h 2003-01-14 09:15:55.000000000 -0500 @@ -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 2003-01-06 16:08:17.000000000 -0500 +++ oskit-20020317-entropy/linux/src/include/linux/random.h 2003-01-14 09:15:55.000000000 -0500 @@ -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 2003-01-06 16:08:19.000000000 -0500 +++ oskit-20020317-entropy/linux/src/include/linux/sched.h 2003-01-14 09:15:55.000000000 -0500 @@ -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 2003-01-06 15:58:19.000000000 -0500 +++ oskit-20020317-entropy/modules.x86.pc 2003-01-14 09:15:55.000000000 -0500 @@ -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 2003-01-06 16:09:04.000000000 -0500 +++ oskit-20020317-entropy/oskit/dev/GUID 2003-01-14 09:15:55.000000000 -0500 @@ -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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/oskit/dev/entropy.h 2003-01-14 09:15:55.000000000 -0500 @@ -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 +#include +#include +#include + +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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/oskit/dev/entropy_channel.h 2003-01-14 09:15:55.000000000 -0500 @@ -0,0 +1,56 @@ +#ifndef _OSKIT_DEV_ENTROPY_CHANNEL_H_ +#define _OSKIT_DEV_ENTROPY_CHANNEL_H_ + +#include +#include +#include +#include + +/* + * 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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/oskit/dev/entropy_stats.h 2003-01-14 09:15:55.000000000 -0500 @@ -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 2003-01-06 16:09:05.000000000 -0500 +++ oskit-20020317-entropy/oskit/dev/linux.h 2003-01-16 13:59:25.000000000 -0500 @@ -60,6 +60,9 @@ void oskit_linux_init_blk(void); void oskit_linux_init_net(void); +/* Initialize one or more entropy devices */ +oskit_error_t oskit_linux_init_entropy(void); +oskit_error_t oskit_linux_init_entropy_random(void); /*** Functions to initialize and register individual device drivers ***/ /* @@ -71,6 +74,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 +88,7 @@ #include #undef driver +oskit_error_t oskit_linux_init_randompools(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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/oskit/dev/linux_entropy.h 2003-01-15 20:03:15.000000000 -0500 @@ -0,0 +1,10 @@ + +/* entropy(, , , , , ) +*/ +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 2003-01-06 16:09:23.000000000 -0500 +++ oskit-20020317-entropy/startup/GNUmakerules 2003-01-14 09:15:55.000000000 -0500 @@ -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 2003-01-06 16:09:24.000000000 -0500 +++ oskit-20020317-entropy/startup/start_devices.c 2003-01-14 09:15:55.000000000 -0500 @@ -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 1969-12-31 19:00:00.000000000 -0500 +++ oskit-20020317-entropy/startup/start_entropy_devices.c 2003-01-15 20:42:55.000000000 -0500 @@ -0,0 +1,38 @@ + +/* + * start_entropy_devices.c + */ + +#include +#include + +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); + _init_devices_entropy = (void (*)(void))oskit_linux_init_entropy; +} +#else +/* + * Use a (dreaded) common symbol + */ +void (*_init_devices_entropy)(void) = oskit_linux_init_entropy; +#endif