1256381Smarkm/*-
2256381Smarkm * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
3256381Smarkm * Copyright (c) 2013 Mark R V Murray
4256381Smarkm * All rights reserved.
5256381Smarkm *
6256381Smarkm * Redistribution and use in source and binary forms, with or without
7256381Smarkm * modification, are permitted provided that the following conditions
8256381Smarkm * are met:
9256381Smarkm * 1. Redistributions of source code must retain the above copyright
10256381Smarkm *    notice, this list of conditions and the following disclaimer
11256381Smarkm *    in this position and unchanged.
12256381Smarkm * 2. Redistributions in binary form must reproduce the above copyright
13256381Smarkm *    notice, this list of conditions and the following disclaimer in the
14256381Smarkm *    documentation and/or other materials provided with the distribution.
15256381Smarkm *
16256381Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17256381Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18256381Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19256381Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20256381Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21256381Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22256381Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23256381Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24256381Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25256381Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26256381Smarkm */
27256381Smarkm
28256381Smarkm#include <sys/param.h>
29256381Smarkm__FBSDID("$FreeBSD$");
30256381Smarkm
31256381Smarkm#include <sys/kernel.h>
32256381Smarkm#include <sys/libkern.h>
33256381Smarkm#include <sys/lock.h>
34256381Smarkm#include <sys/malloc.h>
35256381Smarkm#include <sys/queue.h>
36256381Smarkm#include <sys/random.h>
37256381Smarkm#include <sys/selinfo.h>
38256381Smarkm#include <sys/sx.h>
39256381Smarkm#include <sys/sysctl.h>
40256381Smarkm#include <sys/systm.h>
41256381Smarkm#include <sys/unistd.h>
42256381Smarkm
43256381Smarkm#include <machine/cpu.h>
44256381Smarkm
45256381Smarkm#include <dev/random/randomdev.h>
46256381Smarkm#include <dev/random/randomdev_soft.h>
47256381Smarkm#include <dev/random/random_adaptors.h>
48256381Smarkm#include <dev/random/random_harvestq.h>
49256381Smarkm
50256381Smarkm#include "live_entropy_sources.h"
51256381Smarkm
52256381SmarkmLIST_HEAD(les_head, live_entropy_sources);
53256381Smarkmstatic struct les_head sources = LIST_HEAD_INITIALIZER(sources);
54256381Smarkm
55256381Smarkm/*
56256381Smarkm * The live_lock protects the consistency of the "struct les_head sources"
57256381Smarkm */
58256381Smarkmstatic struct sx les_lock; /* need a sleepable lock */
59256381Smarkm
60256381Smarkmvoid
61256381Smarkmlive_entropy_source_register(struct random_hardware_source *rsource)
62256381Smarkm{
63256381Smarkm	struct live_entropy_sources *les;
64256381Smarkm
65256381Smarkm	KASSERT(rsource != NULL, ("invalid input to %s", __func__));
66256381Smarkm
67256381Smarkm	les = malloc(sizeof(struct live_entropy_sources), M_ENTROPY, M_WAITOK);
68256381Smarkm	les->rsource = rsource;
69256381Smarkm
70256381Smarkm	sx_xlock(&les_lock);
71256381Smarkm	LIST_INSERT_HEAD(&sources, les, entries);
72256381Smarkm	sx_xunlock(&les_lock);
73256381Smarkm}
74256381Smarkm
75256381Smarkmvoid
76256381Smarkmlive_entropy_source_deregister(struct random_hardware_source *rsource)
77256381Smarkm{
78256381Smarkm	struct live_entropy_sources *les = NULL;
79256381Smarkm
80256381Smarkm	KASSERT(rsource != NULL, ("invalid input to %s", __func__));
81256381Smarkm
82256381Smarkm	sx_xlock(&les_lock);
83256381Smarkm	LIST_FOREACH(les, &sources, entries)
84256381Smarkm		if (les->rsource == rsource) {
85256381Smarkm			LIST_REMOVE(les, entries);
86256381Smarkm			break;
87256381Smarkm		}
88256381Smarkm	sx_xunlock(&les_lock);
89256381Smarkm	if (les != NULL)
90256381Smarkm		free(les, M_ENTROPY);
91256381Smarkm}
92256381Smarkm
93256381Smarkmstatic int
94256381Smarkmlive_entropy_source_handler(SYSCTL_HANDLER_ARGS)
95256381Smarkm{
96256381Smarkm	struct live_entropy_sources *les;
97256381Smarkm	int error, count;
98256381Smarkm
99256381Smarkm	count = error = 0;
100256381Smarkm
101256381Smarkm	sx_slock(&les_lock);
102256381Smarkm
103256381Smarkm	if (LIST_EMPTY(&sources))
104256381Smarkm		error = SYSCTL_OUT(req, "", 0);
105256381Smarkm	else {
106256381Smarkm		LIST_FOREACH(les, &sources, entries) {
107256381Smarkm
108256381Smarkm			error = SYSCTL_OUT(req, ",", count++ ? 1 : 0);
109256381Smarkm			if (error)
110256381Smarkm				break;
111256381Smarkm
112256381Smarkm			error = SYSCTL_OUT(req, les->rsource->ident, strlen(les->rsource->ident));
113256381Smarkm			if (error)
114256381Smarkm				break;
115256381Smarkm		}
116256381Smarkm	}
117256381Smarkm
118256381Smarkm	sx_sunlock(&les_lock);
119256381Smarkm
120256381Smarkm	return (error);
121256381Smarkm}
122256381Smarkm
123256381Smarkmstatic void
124256381Smarkmlive_entropy_sources_init(void *unused)
125256381Smarkm{
126256381Smarkm
127256381Smarkm	SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources,
128256381Smarkm	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
129256381Smarkm	    NULL, 0, live_entropy_source_handler, "",
130256381Smarkm	    "List of Active Live Entropy Sources");
131256381Smarkm
132256381Smarkm	sx_init(&les_lock, "live_entropy_sources");
133256381Smarkm}
134256381Smarkm
135256381Smarkm/*
136256381Smarkm * Run through all "live" sources reading entropy for the given
137256381Smarkm * number of rounds, which should be a multiple of the number
138256381Smarkm * of entropy accumulation pools in use; 2 for Yarrow and 32
139256381Smarkm * for Fortuna.
140256381Smarkm *
141256381Smarkm * BEWARE!!!
142256381Smarkm * This function runs inside the RNG thread! Don't do anything silly!
143256381Smarkm * Remember that we are NOT holding harvest_mtx on entry!
144256381Smarkm */
145256381Smarkmvoid
146256381Smarkmlive_entropy_sources_feed(int rounds, event_proc_f entropy_processor)
147256381Smarkm{
148256381Smarkm	static struct harvest event;
149256381Smarkm	static uint8_t buf[HARVESTSIZE];
150256381Smarkm	struct live_entropy_sources *les;
151256381Smarkm	int i, n;
152256381Smarkm
153256381Smarkm	sx_slock(&les_lock);
154256381Smarkm
155256381Smarkm	/*
156256381Smarkm	 * Walk over all of live entropy sources, and feed their output
157256381Smarkm	 * to the system-wide RNG.
158256381Smarkm	 */
159256381Smarkm	LIST_FOREACH(les, &sources, entries) {
160256381Smarkm
161256381Smarkm		for (i = 0; i < rounds; i++) {
162256381Smarkm			/*
163256381Smarkm			 * This should be quick, since it's a live entropy
164256381Smarkm			 * source.
165256381Smarkm			 */
166256381Smarkm			/* FIXME: Whine loudly if this didn't work. */
167256381Smarkm			n = les->rsource->read(buf, sizeof(buf));
168256381Smarkm			n = MIN(n, HARVESTSIZE);
169256381Smarkm
170256381Smarkm			event.somecounter = get_cyclecount();
171256381Smarkm			event.size = n;
172256381Smarkm			event.bits = (n*8)/2;
173256381Smarkm			event.source = les->rsource->source;
174256381Smarkm			memcpy(event.entropy, buf, n);
175256381Smarkm
176256381Smarkm			/* Do the actual entropy insertion */
177256381Smarkm			entropy_processor(&event);
178256381Smarkm		}
179256381Smarkm
180256381Smarkm	}
181256381Smarkm
182256381Smarkm	sx_sunlock(&les_lock);
183256381Smarkm}
184256381Smarkm
185256381Smarkmstatic void
186256381Smarkmlive_entropy_sources_deinit(void *unused)
187256381Smarkm{
188256381Smarkm
189256381Smarkm	sx_destroy(&les_lock);
190256381Smarkm}
191256381Smarkm
192256381SmarkmSYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
193256381Smarkm    live_entropy_sources_init, NULL);
194256381SmarkmSYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
195256381Smarkm    live_entropy_sources_deinit, NULL);
196