patch-2.4.3 linux/drivers/char/i810_rng.c

Next file: linux/drivers/char/istallion.c
Previous file: linux/drivers/char/dz.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.2/linux/drivers/char/i810_rng.c linux/drivers/char/i810_rng.c
@@ -1,184 +1,18 @@
 /*
 
 	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2000 Philipp Rumpf <prumpf@tux.org>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
 	Driver Web site:  http://sourceforge.net/projects/gkernel/
 
-
-
-	Based on:
-	Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet
-		May 1999 Order Number: 290658-002 R
-
-	Intel 82802 Firmware Hub: Random Number Generator
-	Programmer's Reference Manual
-		December 1999 Order Number: 298029-001 R
-
-	Intel 82802 Firmware HUB Random Number Generator Driver
-	Copyright (c) 2000 Matt Sottek <msottek@quiknet.com>
-
-	Special thanks to Matt Sottek.  I did the "guts", he
-	did the "brains" and all the testing.  (Anybody wanna send
-	me an i810 or i820?)
+	Please read Documentation/i810_rng.txt for details on use.
 
 	----------------------------------------------------------
 
 	This software may be used and distributed according to the terms
         of the GNU General Public License, incorporated herein by reference.
 
-	----------------------------------------------------------
-
-	From the firmware hub datasheet:
-
-	The Firmware Hub integrates a Random Number Generator (RNG)
-	using thermal noise generated from inherently random quantum
-	mechanical properties of silicon. When not generating new random
-	bits the RNG circuitry will enter a low power state. Intel will
-	provide a binary software driver to give third party software
-	access to our RNG for use as a security feature. At this time,
-	the RNG is only to be used with a system in an OS-present state.
-
-	----------------------------------------------------------
-
-	Theory of operation:
-
-	This driver has TWO modes of operation:
-
-	Mode 1
-	------
-	Character driver.  Using the standard open()
-	and read() system calls, you can read random data from
-	the i810 RNG device.  This data is NOT CHECKED by any
-	fitness tests, and could potentially be bogus (if the
-	hardware is faulty or has been tampered with).
-
-	/dev/intel_rng is char device major 10, minor 183.
-
-
-	Mode 2
-	------
-	Injection of entropy into the kernel entropy pool via a
-	timer function.
-
-	A timer is run at rng_timer_len intervals, reading 8 bits
-	of data from the RNG.  If the RNG has previously passed a
-	FIPS test, then the data will be added to the /dev/random
-	entropy pool.  Then, those 8 bits are added to an internal
-	test data pool.  When that pool is full, a FIPS test is
-	run to verify that the last N bytes read are decently random.
-
-	Thus, the RNG will never be enabled until it passes a
-	FIPS test.  And, data will stop flowing into the system
-	entropy pool if the data is determined to be non-random.
-
-	Finally, note that the timer defaults to OFF.  This ensures
-	that the system entropy pool will not be polluted with
-	RNG-originated data unless a conscious decision is made
-	by the user.
-
-	HOWEVER NOTE THAT UP TO 2499 BYTES OF DATA CAN BE BOGUS
-	BEFORE THE SYSTEM WILL NOTICE VIA THE FIPS TEST.
-
-	----------------------------------------------------------
-
-	Driver notes:
-
-	* You may enable and disable the RNG timer via sysctl:
-
-		# disable RNG
-		echo 0 > /proc/sys/dev/i810_rng_timer
-
-		# enable RNG
-		echo 1 > /proc/sys/dev/i810_rng_timer
-
-	* The default number of entropy bits added by default is
-	the full 8 bits.  If you wish to reduce this value for
-	paranoia's sake, you can do so via sysctl as well:
-
-		# Add only 4 bits of entropy to /dev/random
-		echo 4 > /proc/sys/dev/i810_rng_entropy
-
-	* The default number of entropy bits can also be set via
-	a module parameter "rng_entropy" at module load time.
-
-	* When the RNG timer is enabled, the driver reads 1 byte
-	from the hardware RNG every N jiffies.  By default, every
-	half-second.  If you would like to change the timer interval,
-	do so via another sysctl:
-
-		echo 200 > /proc/sys/dev/i810_rng_interval
-
-	NOTE THIS VALUE IS IN JIFFIES, NOT SECONDS OR MILLISECONDS.
-	Minimum interval is 1 jiffy, maximum interval is 24 hours.
-
-	* In order to unload the i810_rng module, you must first
-	disable the hardware via sysctl i810_hw_enabled, as shown above,
-	and make sure all users of the character device have closed
-
-	* The timer and the character device may be used simultaneously,
-	if desired.
-
-	* FIXME: support poll()
-
-	* FIXME: should we be crazy and support mmap()?
-
-	* FIXME: It is possible for the timer function to read,
-	and shove into the kernel entropy pool, 2499 bytes of data
-	before the internal FIPS test notices that the data is bad.
-	The kernel should handle this (I think???), but we should use a
-	2500-byte array, and re-run the FIPS test for every byte read.
-	This will slow things down but guarantee that bad data is
-	never passed upstream.
-
-	* FIXME: module unload is racy.  To fix this, struct ctl_table
-	needs an owner member a la struct file_operations.
-
-	* Since the RNG is accessed from a timer as well as normal
-	kernel code, but not from interrupts, we use spin_lock_bh
-	in regular code, and spin_lock in the timer function, to
-	serialize access to the RNG hardware area.
-
-	----------------------------------------------------------
-
-	Change history:
-
-	Version 0.6.2:
-	* Clean up spinlocks.  Since we don't have any interrupts
-	  to worry about, but we do have a timer to worry about,
-	  we use spin_lock_bh everywhere except the timer function
-	  itself.
-	* Fix module load/unload.
-	* Fix timer function and h/w enable/disable logic
-	* New timer interval sysctl
-	* Clean up sysctl names
-
-	Version 0.9.0:
-	* Don't register a pci_driver, because we are really
-	  using PCI bridge vendor/device ids, and someone
-	  may want to register a driver for the bridge. (bug fix)
-	* Don't let the usage count go negative (bug fix)
-	* Clean up spinlocks (bug fix)
-	* Enable PCI device, if necessary (bug fix)
-	* iounmap on module unload (bug fix)
-	* If RNG chrdev is already in use when open(2) is called,
-	  sleep until it is available.
-	* Remove redundant globals rng_allocated, rng_use_count
-	* Convert numeric globals to unsigned
-	* Module unload cleanup
-
-	Version 0.9.1:
-	* Support i815 chipsets too (Matt Sottek)
-	* Fix reference counting when statically compiled (prumpf)
-	* Rewrite rng_dev_read (prumpf)
-	* Make module races less likely (prumpf)
-	* Small miscellaneous bug fixes (prumpf)
-	* Use pci table for PCI id list
-
-	Version 0.9.2:
-	* Simplify open blocking logic
-
  */
 
 
@@ -190,7 +24,6 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/random.h>
-#include <linux/sysctl.h>
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
 #include <linux/mm.h>
@@ -202,7 +35,7 @@
 /*
  * core module and version information
  */
-#define RNG_VERSION "0.9.2"
+#define RNG_VERSION "0.9.5"
 #define RNG_MODULE_NAME "i810_rng"
 #define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
 #define PFX RNG_MODULE_NAME ": "
@@ -211,7 +44,7 @@
 /*
  * debugging macros
  */
-#undef RNG_DEBUG /* define to 1 to enable copious debugging info */
+#undef RNG_DEBUG /* define to enable copious debugging info */
 
 #ifdef RNG_DEBUG
 /* note: prints function name for you */
@@ -220,8 +53,8 @@
 #define DPRINTK(fmt, args...)
 #endif
 
-#define RNG_NDEBUG 0        /* define to 1 to disable lightweight runtime checks */
-#if RNG_NDEBUG
+#undef RNG_NDEBUG        /* define to disable lightweight runtime checks */
+#ifdef RNG_NDEBUG
 #define assert(expr)
 #else
 #define assert(expr) \
@@ -233,13 +66,6 @@
 
 
 /*
- * prototypes
- */
-static void rng_fips_test_store (int rng_data);
-static void rng_run_fips_test (void);
-
-
-/*
  * RNG registers (offsets from rng_mem)
  */
 #define RNG_HW_STATUS			0
@@ -249,6 +75,9 @@
 #define		RNG_DATA_PRESENT	0x01
 #define RNG_DATA			2
 
+/*
+ * Magic address at which Intel PCI bridges locate the RNG
+ */
 #define RNG_ADDR			0xFFBC015F
 #define RNG_ADDR_LEN			3
 
@@ -258,13 +87,6 @@
 
 
 /*
- * Frequency that data is added to kernel entropy pool
- * HZ>>1 == every half-second
- */
-#define RNG_DEF_TIMER_LEN		(HZ >> 1)
-
-
-/*
  * number of bytes required for a FIPS test.
  * do not alter unless you really, I mean
  * REALLY know what you are doing.
@@ -277,18 +99,7 @@
  * as we only support a single RNG device
  */
 static int rng_hw_enabled;		/* is the RNG h/w enabled? */
-static int rng_timer_enabled;		/* is the RNG timer enabled? */
-static int rng_trusted;			/* does FIPS trust out data? */
-static int rng_enabled_sysctl;		/* sysctl for enabling/disabling RNG */
-static unsigned int rng_entropy = 8;	/* number of entropy bits we submit to /dev/random */
-static unsigned int rng_entropy_sysctl;	/* sysctl for changing entropy bits */
-static unsigned int rng_interval_sysctl; /* sysctl for changing timer interval */
-static int rng_have_mem_region;		/* did we grab RNG region via request_mem_region? */
-static unsigned int rng_fips_counter;	/* size of internal FIPS test data pool */
-static unsigned int rng_timer_len = RNG_DEF_TIMER_LEN; /* timer interval, in jiffies */
 static void *rng_mem;			/* token to our ioremap'd RNG register area */
-static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; /* hardware lock */
-static struct timer_list rng_timer;	/* kernel timer for RNG hardware reads and tests */
 static struct pci_dev *rng_pdev;	/* Firmware Hub PCI device found during PCI probe */
 static struct semaphore rng_open_sem;	/* Semaphore for serializing rng_open/release */
 
@@ -313,7 +124,7 @@
 static inline int rng_data_present (void)
 {
 	assert (rng_mem != NULL);
-	assert (rng_hw_enabled == 1);
+	assert (rng_hw_enabled > 0);
 
 	return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0;
 }
@@ -322,55 +133,13 @@
 static inline int rng_data_read (void)
 {
 	assert (rng_mem != NULL);
-	assert (rng_hw_enabled == 1);
+	assert (rng_hw_enabled > 0);
 
 	return readb (rng_mem + RNG_DATA);
 }
 
 
 /*
- * rng_timer_ticker - executes every rng_timer_len jiffies,
- *		      adds a single byte to system entropy
- *		      and internal FIPS test pools
- */
-static void rng_timer_tick (unsigned long data)
-{
-	int rng_data;
-
-	spin_lock (&rng_lock);
-
-	if (rng_data_present ()) {
-		/* gimme some thermal noise, baby */
-		rng_data = rng_data_read ();
-
-		spin_unlock (&rng_lock);
-
-		/*
-		 * if RNG has been verified in the past, add
-		 * data just read to the /dev/random pool,
-		 * with the entropy specified by the user
-		 * via sysctl (defaults to 8 bits)
-		 */
-		if (rng_trusted)
-			batch_entropy_store (rng_data, jiffies, rng_entropy);
-
-		/* fitness testing via FIPS, if we have enough data */
-		rng_fips_test_store (rng_data);
-		if (rng_fips_counter > RNG_FIPS_TEST_THRESHOLD)
-			rng_run_fips_test ();
-	} else {
-		spin_unlock (&rng_lock);
-	}
-
-	/* run the timer again, if enabled */
-	if (rng_timer_enabled) {
-		rng_timer.expires = jiffies + rng_timer_len;
-		add_timer (&rng_timer);
-	}
-}
-
-
-/*
  * rng_enable - enable or disable the RNG hardware
  */
 static int rng_enable (int enable)
@@ -380,8 +149,6 @@
 
 	DPRINTK ("ENTER\n");
 
-	spin_lock_bh (&rng_lock);
-
 	hw_status = rng_hwstatus ();
 
 	if (enable) {
@@ -406,18 +173,16 @@
 
 	new_status = rng_hwstatus ();
 
-	spin_unlock_bh (&rng_lock);
-
-	if (action == 1)
-		printk (KERN_INFO PFX "RNG h/w enabled\n");
-	else if (action == 2)
-		printk (KERN_INFO PFX "RNG h/w disabled\n");
-
-	/* too bad C doesn't have ^^ */
-	if ((!enable) != (!(new_status & RNG_ENABLED))) {
-		printk (KERN_ERR PFX "Unable to %sable the RNG\n",
-			enable ? "en" : "dis");
-		rc = -EIO;
+	if (action == 1) {
+		if (new_status & RNG_ENABLED)
+			printk (KERN_INFO PFX "RNG h/w enabled\n");
+		else
+			printk (KERN_ERR PFX "Unable to enable the RNG\n");
+	} else if (action == 2) {
+		if ((new_status & RNG_ENABLED) == 0)
+			printk (KERN_INFO PFX "RNG h/w disabled\n");
+		else
+			printk (KERN_ERR PFX "Unable to disable the RNG\n");
 	}
 
 	DPRINTK ("EXIT, returning %d\n", rc);
@@ -425,209 +190,12 @@
 }
 
 
-/*
- * rng_handle_sysctl_enable - handle a read or write of our enable/disable sysctl
- */
-
-static int rng_handle_sysctl_enable (ctl_table * table, int write, struct file *filp,
-				     void *buffer, size_t * lenp)
-{
-	int enabled_save, rc;
-
-	DPRINTK ("ENTER\n");
-
-	MOD_INC_USE_COUNT;
-	spin_lock_bh (&rng_lock);
-	rng_enabled_sysctl = enabled_save = rng_timer_enabled;
-	spin_unlock_bh (&rng_lock);
-
-	rc = proc_dointvec (table, write, filp, buffer, lenp);
-	if (rc)
-		return rc;
-
-	spin_lock_bh (&rng_lock);
-	if (enabled_save != rng_enabled_sysctl) {
-		rng_timer_enabled = rng_enabled_sysctl;
-		spin_unlock_bh (&rng_lock);
-
-		/* enable/disable hardware */
-		rng_enable (rng_enabled_sysctl);
-
-		/* enable/disable timer */
-		if (rng_enabled_sysctl) {
-			rng_timer.expires = jiffies + rng_timer_len;
-			add_timer (&rng_timer);
-		} else {
-			del_timer_sync (&rng_timer);
-		}
-	} else {
-		spin_unlock_bh (&rng_lock);
-	}
-
-	/* This needs to be in a higher layer */
-	MOD_DEC_USE_COUNT;
-
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-}
-
-
-/*
- * rng_handle_sysctl_entropy - handle a read or write of our entropy bits sysctl
- */
-
-static int rng_handle_sysctl_entropy (ctl_table * table, int write, struct file *filp,
-				      void *buffer, size_t * lenp)
-{
-	int entropy_bits_save, rc;
-
-	DPRINTK ("ENTER\n");
-
-	spin_lock_bh (&rng_lock);
-	rng_entropy_sysctl = entropy_bits_save = rng_entropy;
-	spin_unlock_bh (&rng_lock);
-
-	rc = proc_dointvec (table, write, filp, buffer, lenp);
-	if (rc)
-		return rc;
-
-	if (entropy_bits_save == rng_entropy_sysctl)
-		goto out;
-
-	if ((rng_entropy_sysctl >= 0) &&
-    	    (rng_entropy_sysctl <= 8)) {
-		spin_lock_bh (&rng_lock);
-		rng_entropy = rng_entropy_sysctl;
-		spin_unlock_bh (&rng_lock);
-
-		printk (KERN_INFO PFX "entropy bits now %d\n", rng_entropy_sysctl);
-	} else {
-		printk (KERN_INFO PFX "ignoring invalid entropy setting (%d)\n",
-			rng_entropy_sysctl);
-	}
-
-out:
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-}
-
-/*
- * rng_handle_sysctl_interval - handle a read or write of our timer interval len sysctl
- */
-
-static int rng_handle_sysctl_interval (ctl_table * table, int write, struct file *filp,
-				      void *buffer, size_t * lenp)
-{
-	int timer_len_save, rc;
-
-	DPRINTK ("ENTER\n");
-
-	spin_lock_bh (&rng_lock);
-	rng_interval_sysctl = timer_len_save = rng_timer_len;
-	spin_unlock_bh (&rng_lock);
-
-	rc = proc_dointvec (table, write, filp, buffer, lenp);
-	if (rc)
-		return rc;
-
-	if (timer_len_save == rng_interval_sysctl)
-		goto out;
-
-	if ((rng_interval_sysctl > 0) &&
-    	    (rng_interval_sysctl < (HZ*86400))) {
-		spin_lock_bh (&rng_lock);
-		rng_timer_len = rng_interval_sysctl;
-		spin_unlock_bh (&rng_lock);
-
-		printk (KERN_INFO PFX "timer interval now %d\n", rng_interval_sysctl);
-	} else {
-		printk (KERN_INFO PFX "ignoring invalid timer interval (%d)\n",
-			rng_interval_sysctl);
-	}
-
-out:
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-}
-
-
-/*
- * rng_sysctl - add or remove the rng sysctl
- */
-static void rng_sysctl (int add)
-{
-#define DEV_I810_TIMER		1
-#define DEV_I810_ENTROPY	2
-#define DEV_I810_INTERVAL	3
-
-	/* Definition of the sysctl */
-	/* FIXME: use new field:value style of struct initialization */
-	static ctl_table rng_sysctls[] = {
-		{DEV_I810_TIMER,		/* ID */
-		 RNG_MODULE_NAME "_timer",	/* name in /proc */
-		 &rng_enabled_sysctl,
-		 sizeof (rng_enabled_sysctl),	/* data ptr, data size */
-		 0644,				/* mode */
-		 0,				/* child */
-		 rng_handle_sysctl_enable,	/* proc handler */
-		 0,				/* strategy */
-		 0,				/* proc control block */
-		 0, 0}
-		,
-		{DEV_I810_ENTROPY,		/* ID */
-		 RNG_MODULE_NAME "_entropy",	/* name in /proc */
-		 &rng_entropy_sysctl,
-		 sizeof (rng_entropy_sysctl),	/* data ptr, data size */
-		 0644,				/* mode */
-		 0,				/* child */
-		 rng_handle_sysctl_entropy,	/* proc handler */
-		 0,				/* strategy */
-		 0,				/* proc control block */
-		 0, 0}
-		,
-		{DEV_I810_INTERVAL,		/* ID */
-		 RNG_MODULE_NAME "_interval",	/* name in /proc */
-		 &rng_interval_sysctl,
-		 sizeof (rng_interval_sysctl),	/* data ptr, data size */
-		 0644,				/* mode */
-		 0,				/* child */
-		 rng_handle_sysctl_interval,	/* proc handler */
-		 0,				/* strategy */
-		 0,				/* proc control block */
-		 0, 0}
-		,
-		{0}
-	};
-
-	/* Define the parent file : /proc/sys/dev */
-	static ctl_table sysctls_root[] = {
-		{CTL_DEV,
-		 "dev",
-		 NULL, 0,
-		 0555,
-		 rng_sysctls},
-		{0}
-	};
-	static struct ctl_table_header *sysctls_root_header = NULL;
-
-	if (add) {
-		if (!sysctls_root_header)
-			sysctls_root_header = register_sysctl_table (sysctls_root, 0);
-	} else if (sysctls_root_header) {
-		unregister_sysctl_table (sysctls_root_header);
-		sysctls_root_header = NULL;
-	}
-}
-
-
 static int rng_dev_open (struct inode *inode, struct file *filp)
 {
-	int rc = -EINVAL;
-
 	if ((filp->f_mode & FMODE_READ) == 0)
-		return rc;
+		return -EINVAL;
 	if (filp->f_mode & FMODE_WRITE)
-		return rc;
+		return -EINVAL;
 
 	/* wait for device to become free */
 	if (filp->f_flags & O_NONBLOCK) {
@@ -639,15 +207,11 @@
 	}
 
 	if (rng_enable (1)) {
-		rc = -EIO;
-		goto err_out;
+		up (&rng_open_sem);
+		return -EIO;
 	}
 
 	return 0;
-
-err_out:
-	up (&rng_open_sem);
-	return rc;
 }
 
 
@@ -662,12 +226,13 @@
 static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size,
 			     loff_t * offp)
 {
+	static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED;
 	int have_data;
 	u8 data = 0;
 	ssize_t ret = 0;
 
 	while (size) {
-		spin_lock_bh (&rng_lock);
+		spin_lock (&rng_lock);
 
 		have_data = 0;
 		if (rng_data_present ()) {
@@ -675,7 +240,7 @@
 			have_data = 1;
 		}
 
-		spin_unlock_bh (&rng_lock);
+		spin_unlock (&rng_lock);
 
 		if (have_data) {
 			if (put_user (data, buf++)) {
@@ -686,20 +251,35 @@
 			ret++;
 		}
 
-		if (current->need_resched)
-			schedule ();
+		if (filp->f_flags & O_NONBLOCK)
+			return ret ? : -EAGAIN;
+
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
 
 		if (signal_pending (current))
 			return ret ? : -ERESTARTSYS;
-
-		if (filp->f_flags & O_NONBLOCK)
-			return ret ? : -EAGAIN;
 	}
 
 	return ret;
 }
 
 
+static struct file_operations rng_chrdev_ops = {
+	owner:		THIS_MODULE,
+	open:		rng_dev_open,
+	release:	rng_dev_release,
+	read:		rng_dev_read,
+};
+
+
+static struct miscdevice rng_miscdev = {
+	RNG_MISCDEV_MINOR,
+	RNG_MODULE_NAME,
+	&rng_chrdev_ops,
+};
+
+
 /*
  * rng_init_one - look for and attempt to init a single RNG
  */
@@ -710,19 +290,19 @@
 
 	DPRINTK ("ENTER\n");
 
-	if (pci_enable_device (dev))
-		return -EIO;
-
-	/* XXX currently fails, investigate who has our mem region */
-	if (request_mem_region (RNG_ADDR, RNG_ADDR_LEN, RNG_MODULE_NAME))
-		rng_have_mem_region = 1;
+	rc = misc_register (&rng_miscdev);
+	if (rc) {
+		printk (KERN_ERR PFX "cannot register misc device\n");
+		DPRINTK ("EXIT, returning %d\n", rc);
+		goto err_out;
+	}
 
 	rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN);
 	if (rng_mem == NULL) {
 		printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
 		DPRINTK ("EXIT, returning -EBUSY\n");
 		rc = -EBUSY;
-		goto err_out_free_res;
+		goto err_out_free_miscdev;
 	}
 
 	/* Check for Intel 82802 */
@@ -734,13 +314,6 @@
 		goto err_out_free_map;
 	}
 
-	if (rng_entropy < 0 || rng_entropy > RNG_MAX_ENTROPY)
-		rng_entropy = RNG_MAX_ENTROPY;
-
-	/* init core RNG timer, but do not add it */
-	init_timer (&rng_timer);
-	rng_timer.function = rng_timer_tick;
-
 	/* turn RNG h/w off, if it's on */
 	rc = rng_enable (0);
 	if (rc) {
@@ -748,17 +321,14 @@
 		goto err_out_free_map;
 	}
 
-	/* add sysctls */
-	rng_sysctl (1);
-
 	DPRINTK ("EXIT, returning 0\n");
 	return 0;
 
 err_out_free_map:
 	iounmap (rng_mem);
-err_out_free_res:
-	if (rng_have_mem_region)
-		release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
+err_out_free_miscdev:
+	misc_deregister (&rng_miscdev);
+err_out:
 	return rc;
 }
 
@@ -771,7 +341,7 @@
  * register a pci_driver, because someone else might one day
  * want to register another driver on the same PCI id.
  */
-const static struct pci_device_id rng_pci_tbl[] __initdata = {
+static struct pci_device_id rng_pci_tbl[] __initdata = {
 	{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0x8086, 0x1130, PCI_ANY_ID, PCI_ANY_ID, },
@@ -780,25 +350,8 @@
 MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
 
 
-MODULE_AUTHOR("Jeff Garzik, Matt Sottek");
+MODULE_AUTHOR("Jeff Garzik, Philipp Rumpf, Matt Sottek");
 MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver");
-MODULE_PARM(rng_entropy, "1i");
-MODULE_PARM_DESC(rng_entropy, "Bits of entropy to add to random pool per RNG byte (range: 0-8, default 8)");
-
-
-static struct file_operations rng_chrdev_ops = {
-	owner:		THIS_MODULE,
-	open:		rng_dev_open,
-	release:	rng_dev_release,
-	read:		rng_dev_read,
-};
-
-
-static struct miscdevice rng_miscdev = {
-	RNG_MISCDEV_MINOR,
-	RNG_MODULE_NAME,
-	&rng_chrdev_ops,
-};
 
 
 /*
@@ -826,15 +379,6 @@
 	if (rc)
 		return rc;
 
-	rc = misc_register (&rng_miscdev);
-	if (rc) {
-		iounmap (rng_mem);
-		if (rng_have_mem_region)
-			release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
-		DPRINTK ("EXIT, returning %d\n", rc);
-		return rc;
-	}
-
 	printk (KERN_INFO RNG_DRIVER_NAME " loaded\n");
 
 	rng_pdev = pdev;
@@ -851,16 +395,13 @@
 {
 	DPRINTK ("ENTER\n");
 
-	assert (rng_timer_enabled == 0);
 	assert (rng_hw_enabled == 0);
 
 	misc_deregister (&rng_miscdev);
 
-	rng_sysctl (0);
-
 	iounmap (rng_mem);
-	if (rng_have_mem_region)
-		release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
+
+	rng_pdev = NULL;
 
 	DPRINTK ("EXIT\n");
 }
@@ -868,136 +409,3 @@
 
 module_init (rng_init);
 module_exit (rng_cleanup);
-
-
-
-
-/* These are the startup tests suggested by the FIPS 140-1 spec section
-*  4.11.1 (http://csrc.nist.gov/fips/fips1401.htm)
-*  The Monobit, Poker, Runs, and Long Runs tests are implemented below.
-*  This test is run at periodic intervals to verify
-*  data is sufficiently random. If the tests are failed the RNG module
-*  will no longer submit data to the entropy pool, but the tests will
-*  continue to run at the given interval. If at a later time the RNG
-*  passes all tests it will be re-enabled for the next period.
-*   The reason for this is that it is not unlikely that at some time
-*  during normal operation one of the tests will fail. This does not
-*  necessarily mean the RNG is not operating properly, it is just a
-*  statistically rare event. In that case we don't want to forever
-*  disable the RNG, we will just leave it disabled for the period of
-*  time until the tests are rerun and passed.
-*
-*  For argument sake I tested /dev/urandom with these tests and it
-*  took 142,095 tries before I got a failure, and urandom isn't as
-*  random as random :)
-*/
-
-static int poker[16] = { 0, }, runs[12] = { 0, };
-static int ones = 0, rlength = -1, current_bit = 0, rng_test = 0;
-
-
-/*
- * rng_fips_test_store - store 8 bits of entropy in FIPS
- * 			 internal test data pool
- */
-static void rng_fips_test_store (int rng_data)
-{
-	int j;
-	static int last_bit = 0;
-
-	DPRINTK ("ENTER, rng_data = %d\n", rng_data);
-
-	poker[rng_data >> 4]++;
-	poker[rng_data & 15]++;
-
-	/* Note in the loop below rlength is always one less than the actual
-	   run length. This makes things easier. */
-	last_bit = (rng_data & 128) >> 7;
-	for (j = 7; j >= 0; j--) {
-		ones += current_bit = (rng_data & 1 << j) >> j;
-		if (current_bit != last_bit) {
-			/* If runlength is 1-6 count it in correct bucket. 0's go in
-			   runs[0-5] 1's go in runs[6-11] hence the 6*current_bit below */
-			if (rlength < 5) {
-				runs[rlength +
-				     (6 * current_bit)]++;
-			} else {
-				runs[5 + (6 * current_bit)]++;
-			}
-
-			/* Check if we just failed longrun test */
-			if (rlength >= 33)
-				rng_test &= 8;
-			rlength = 0;
-			/* flip the current run type */
-			last_bit = current_bit;
-		} else {
-			rlength++;
-		}
-	}
-
-	DPRINTK ("EXIT\n");
-}
-
-
-/*
- * now that we have some data, run a FIPS test
- */
-static void rng_run_fips_test (void)
-{
-	int j, i;
-
-	DPRINTK ("ENTER\n");
-
-	/* add in the last (possibly incomplete) run */
-	if (rlength < 5)
-		runs[rlength + (6 * current_bit)]++;
-	else {
-		runs[5 + (6 * current_bit)]++;
-		if (rlength >= 33)
-			rng_test &= 8;
-	}
-	/* Ones test */
-	if ((ones >= 10346) || (ones <= 9654))
-		rng_test &= 1;
-	/* Poker calcs */
-	for (i = 0, j = 0; i < 16; i++)
-		j += poker[i] * poker[i];
-	if ((j >= 1580457) || (j <= 1562821))
-		rng_test &= 2;
-	if ((runs[0] < 2267) || (runs[0] > 2733) ||
-	    (runs[1] < 1079) || (runs[1] > 1421) ||
-	    (runs[2] < 502) || (runs[2] > 748) ||
-	    (runs[3] < 223) || (runs[3] > 402) ||
-	    (runs[4] < 90) || (runs[4] > 223) ||
-	    (runs[5] < 90) || (runs[5] > 223) ||
-	    (runs[6] < 2267) || (runs[6] > 2733) ||
-	    (runs[7] < 1079) || (runs[7] > 1421) ||
-	    (runs[8] < 502) || (runs[8] > 748) ||
-	    (runs[9] < 223) || (runs[9] > 402) ||
-	    (runs[10] < 90) || (runs[10] > 223) ||
-	    (runs[11] < 90) || (runs[11] > 223)) {
-		rng_test &= 4;
-	}
-
-	rng_test = !rng_test;
-	DPRINTK ("FIPS test %sed\n", rng_test ? "pass" : "fail");
-
-	/* enable/disable RNG with results of the tests */
-	if (rng_test && !rng_trusted)
-		printk (KERN_WARNING PFX "FIPS test passed, enabling RNG\n");
-	else if (!rng_test && rng_trusted)
-		printk (KERN_WARNING PFX "FIPS test failed, disabling RNG\n");
-
-	rng_trusted = rng_test;
-
-	/* finally, clear out FIPS variables for start of next run */
-	memset (poker, 0, sizeof (poker));
-	memset (runs, 0, sizeof (runs));
-	ones = 0;
-	rlength = -1;
-	current_bit = 0;
-	rng_test = 0;
-
-	DPRINTK ("EXIT\n");
-}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)