aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/random/randomdev.c
diff options
context:
space:
mode:
authorMark Murray <markm@FreeBSD.org>2014-10-30 21:21:53 +0000
committerMark Murray <markm@FreeBSD.org>2014-10-30 21:21:53 +0000
commit10cb24248a6f13974e11c255c8014cfefe6420a7 (patch)
treed5dfa61a018a7d209b25f173c6ee76709037035a /sys/dev/random/randomdev.c
parent39d22d86ab05fb09689a9882909dfd35ab546ade (diff)
Notes
Diffstat (limited to 'sys/dev/random/randomdev.c')
-rw-r--r--sys/dev/random/randomdev.c271
1 files changed, 145 insertions, 126 deletions
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c
index b76cb839a02c..bc41d511a8f1 100644
--- a/sys/dev/random/randomdev.c
+++ b/sys/dev/random/randomdev.c
@@ -26,9 +26,28 @@
*
*/
+/*
+ * NOTE NOTE NOTE
+ *
+ * This file is compiled into the kernel unconditionally. Any random(4)
+ * infrastructure that needs to be in the kernel by default goes here!
+ *
+ * Except ...
+ *
+ * The adaptor code all goes into random_adaptor.c, which is also compiled
+ * the kernel by default. The module in that file is initialised before
+ * this one.
+ *
+ * Other modules must be initialised after the above two, and are
+ * software random processors which plug into random_adaptor.c.
+ *
+ */
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_random.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -38,196 +57,196 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/lock.h>
-#include <sys/malloc.h>
#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/poll.h>
-#include <sys/priv.h>
+#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/unistd.h>
-#include <machine/bus.h>
-#include <machine/cpu.h>
-
#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/random_harvestq.h>
-#include <dev/random/live_entropy_sources.h>
#define RANDOM_MINOR 0
-static d_read_t random_read;
-static d_write_t random_write;
-static d_ioctl_t random_ioctl;
-static d_poll_t random_poll;
+static d_ioctl_t randomdev_ioctl;
static struct cdevsw random_cdevsw = {
- .d_version = D_VERSION,
- .d_read = random_read,
- .d_write = random_write,
- .d_ioctl = random_ioctl,
- .d_poll = random_poll,
.d_name = "random",
+ .d_version = D_VERSION,
+ .d_read = random_adaptor_read,
+ .d_write = random_adaptor_write,
+ .d_poll = random_adaptor_poll,
+ .d_ioctl = randomdev_ioctl,
};
/* For use with make_dev(9)/destroy_dev(9). */
static struct cdev *random_dev;
+/* Set up the sysctl root node for the entropy device */
+SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator");
+
+MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
+
/* ARGSUSED */
static int
-random_read(struct cdev *dev __unused, struct uio *uio, int flag)
+randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
+ int flags __unused, struct thread *td __unused)
{
- int c, error = 0;
- void *random_buf;
-
- /* Blocking logic */
- if (!random_adaptor->seeded)
- error = (*random_adaptor->block)(flag);
-
- /* The actual read */
- if (!error) {
-
- random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
+ int error = 0;
- while (uio->uio_resid > 0 && !error) {
- c = MIN(uio->uio_resid, PAGE_SIZE);
- c = (*random_adaptor->read)(random_buf, c);
- error = uiomove(random_buf, c, uio);
- }
- /* Finished reading; let the source know so it can do some
- * optional housekeeping */
- (*random_adaptor->read)(NULL, 0);
+ switch (cmd) {
+ /* Really handled in upper layer */
+ case FIOASYNC:
+ case FIONBIO:
+ break;
- free(random_buf, M_ENTROPY);
+ default:
+ error = ENOTTY;
}
return (error);
}
-/* ARGSUSED */
-static int
-random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused)
+/* Helper routine to enable kproc_exit() to work while the module is
+ * being (or has been) unloaded.
+ * This routine is in this file because it is always linked into the kernel,
+ * and will thus never be unloaded. This is critical for unloadable modules
+ * that have threads.
+ */
+void
+randomdev_set_wakeup_exit(void *control)
{
- /* We used to allow this to insert userland entropy.
- * We don't any more because (1) this so-called entropy
- * is usually lousy and (b) its vaguely possible to
- * mess with entropy harvesting by overdoing a write.
- * Now we just ignore input like /dev/null does.
- */
- uio->uio_resid = 0;
-
- return (0);
+ wakeup(control);
+ kproc_exit(0);
+ /* NOTREACHED */
}
/* ARGSUSED */
static int
-random_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
- int flags __unused, struct thread *td __unused)
+randomdev_modevent(module_t mod __unused, int type, void *data __unused)
{
int error = 0;
- switch (cmd) {
- /* Really handled in upper layer */
- case FIOASYNC:
- case FIONBIO:
+ switch (type) {
+ case MOD_LOAD:
+ printf("random: entropy device infrastructure driver\n");
+ random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
+ RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0644, "random");
+ make_dev_alias(random_dev, "urandom"); /* compatibility */
+ random_adaptors_init();
break;
+
+ case MOD_UNLOAD:
+ random_adaptors_deinit();
+ destroy_dev(random_dev);
+ break;
+
+ case MOD_SHUTDOWN:
+ break;
+
default:
- error = ENOTTY;
+ error = EOPNOTSUPP;
+ break;
+
}
+
return (error);
}
-/* ARGSUSED */
-static int
-random_poll(struct cdev *dev __unused, int events, struct thread *td)
-{
- int revents = 0;
+#define EARLY_2_DEV_MODULE(name, evh, arg) \
+static moduledata_t name##_mod = { \
+ #name, \
+ evh, \
+ arg \
+}; \
+DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND)
- if (events & (POLLIN | POLLRDNORM)) {
- if (random_adaptor->seeded)
- revents = events & (POLLIN | POLLRDNORM);
- else
- revents = (*random_adaptor->poll)(events, td);
- }
- return (revents);
-}
+EARLY_2_DEV_MODULE(randomdev, randomdev_modevent, NULL);
+MODULE_VERSION(randomdev, 1);
+
+/* ================
+ * Harvesting stubs
+ * ================
+ */
+/* Internal stub/fake routine for when no entropy processor is loaded.
+ * If the entropy device is not loaded, don't act on harvesting calls
+ * and just return.
+ */
+/* ARGSUSED */
static void
-random_initialize(void *p, struct random_adaptor *s)
+random_harvest_phony(const void *entropy __unused, u_int count __unused,
+ u_int bits __unused, enum random_entropy_source origin __unused)
{
- static int random_inited = 0;
-
- if (random_inited) {
- printf("random: <%s> already initialized\n",
- random_adaptor->ident);
- return;
- }
+}
- random_adaptor = s;
+/* Hold the address of the routine which is actually called */
+static void (*reap_func)(const void *, u_int, u_int, enum random_entropy_source) = random_harvest_phony;
- (s->init)();
+/* Initialise the harvester when/if it is loaded */
+void
+randomdev_init_harvester(void (*reaper)(const void *, u_int, u_int, enum random_entropy_source))
+{
- printf("random: <%s> initialized\n", s->ident);
+ reap_func = reaper;
+}
- /* Use an appropriately evil mode for those who are concerned
- * with daemons */
- random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
- RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random");
- make_dev_alias(random_dev, "urandom"); /* compatibility */
+/* Deinitialise the harvester when/if it is unloaded */
+void
+randomdev_deinit_harvester(void)
+{
- /* mark random(4) as initialized, to avoid being called again */
- random_inited = 1;
+ reap_func = random_harvest_phony;
}
-/* ARGSUSED */
-static int
-random_modevent(module_t mod __unused, int type, void *data __unused)
+/* Entropy harvesting routine.
+ * Implemented as in indirect call to allow non-inclusion of
+ * the entropy device.
+ */
+void
+random_harvest(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin)
{
- static eventhandler_tag attach_tag = NULL;
- int error = 0;
-
- switch (type) {
- case MOD_LOAD:
- random_adaptor_choose(&random_adaptor);
- if (random_adaptor == NULL) {
- printf("random: No random adaptor attached, "
- "postponing initialization\n");
- attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach,
- random_initialize, NULL, EVENTHANDLER_PRI_ANY);
- } else
- random_initialize(NULL, random_adaptor);
+ (*reap_func)(entropy, count, bits, origin);
+}
- break;
+/* ================================
+ * Internal reading stubs and fakes
+ * ================================
+ */
- case MOD_UNLOAD:
- if (random_adaptor != NULL) {
- (*random_adaptor->deinit)();
- destroy_dev(random_dev);
- }
- /* Unregister the event handler */
- if (attach_tag != NULL)
- EVENTHANDLER_DEREGISTER(random_adaptor_attach,
- attach_tag);
+/* Hold the address of the routine which is actually called */
+static u_int (*read_func)(uint8_t *, u_int) = dummy_random_read_phony;
- break;
+/* Initialise the reader when/if it is loaded */
+void
+randomdev_init_reader(u_int (*reader)(uint8_t *, u_int))
+{
- case MOD_SHUTDOWN:
- break;
+ read_func = reader;
+}
- default:
- error = EOPNOTSUPP;
- break;
+/* Deinitialise the reader when/if it is unloaded */
+void
+randomdev_deinit_reader(void)
+{
- }
- return (error);
+ read_func = dummy_random_read_phony;
}
-DEV_MODULE(random, random_modevent, NULL);
-MODULE_VERSION(random, 1);
+/* Kernel API version of read_random().
+ * Implemented as in indirect call to allow non-inclusion of
+ * the entropy device.
+ */
+int
+read_random(void *buf, int count)
+{
+
+ return ((int)(*read_func)(buf, (u_int)count));
+}