| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: kern_rndsink.c,v 1.10 2014/10/26 18:22:32 tls Exp $ */ | | 1 | /* $NetBSD: kern_rndsink.c,v 1.11 2015/04/13 14:41:06 riastradh Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Taylor R. Campbell. | | 8 | * by Taylor R. Campbell. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -20,27 +20,27 @@ | | | @@ -20,27 +20,27 @@ |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: kern_rndsink.c,v 1.10 2014/10/26 18:22:32 tls Exp $"); | | 33 | __KERNEL_RCSID(0, "$NetBSD: kern_rndsink.c,v 1.11 2015/04/13 14:41:06 riastradh Exp $"); |
34 | | | 34 | |
35 | #include <sys/param.h> | | 35 | #include <sys/param.h> |
36 | #include <sys/types.h> | | 36 | #include <sys/types.h> |
37 | #include <sys/condvar.h> | | 37 | #include <sys/condvar.h> |
38 | #include <sys/kmem.h> | | 38 | #include <sys/kmem.h> |
39 | #include <sys/mutex.h> | | 39 | #include <sys/mutex.h> |
40 | #include <sys/queue.h> | | 40 | #include <sys/queue.h> |
41 | #include <sys/rnd.h> | | 41 | #include <sys/rnd.h> |
42 | #include <sys/rndsink.h> | | 42 | #include <sys/rndsink.h> |
43 | | | 43 | |
44 | #include <dev/rnd_private.h> /* XXX provisional, for rnd_extract_data */ | | 44 | #include <dev/rnd_private.h> /* XXX provisional, for rnd_extract_data */ |
45 | | | 45 | |
46 | enum rsink_state { | | 46 | enum rsink_state { |
| @@ -76,108 +76,40 @@ static TAILQ_HEAD(, rndsink) rndsinks = | | | @@ -76,108 +76,40 @@ static TAILQ_HEAD(, rndsink) rndsinks = |
76 | void | | 76 | void |
77 | rndsinks_init(void) | | 77 | rndsinks_init(void) |
78 | { | | 78 | { |
79 | | | 79 | |
80 | /* | | 80 | /* |
81 | * This mutex must be at an ipl as high as the highest ipl of | | 81 | * This mutex must be at an ipl as high as the highest ipl of |
82 | * anyone who wants to call rndsink_request. | | 82 | * anyone who wants to call rndsink_request. |
83 | * | | 83 | * |
84 | * XXX Call this IPL_RND, perhaps. | | 84 | * XXX Call this IPL_RND, perhaps. |
85 | */ | | 85 | */ |
86 | mutex_init(&rndsinks_lock, MUTEX_DEFAULT, IPL_VM); | | 86 | mutex_init(&rndsinks_lock, MUTEX_DEFAULT, IPL_VM); |
87 | } | | 87 | } |
88 | | | 88 | |
89 | /* | | | |
90 | * XXX Provisional -- rndpool_extract and rndpool_maybe_extract should | | | |
91 | * move into kern_rndpool.c. | | | |
92 | */ | | | |
93 | extern rndpool_t rnd_pool; | | | |
94 | extern kmutex_t rndpool_mtx; | | | |
95 | | | | |
96 | /* | | | |
97 | * Fill the buffer with as much entropy as we can. Return true if it | | | |
98 | * has full entropy and false if not. | | | |
99 | */ | | | |
100 | static bool | | | |
101 | rndpool_extract(void *buffer, size_t bytes) | | | |
102 | { | | | |
103 | const size_t extracted = rnd_extract_data(buffer, bytes, | | | |
104 | RND_EXTRACT_GOOD); | | | |
105 | | | | |
106 | if (extracted < bytes) { | | | |
107 | (void)rnd_extract_data((uint8_t *)buffer + extracted, | | | |
108 | bytes - extracted, RND_EXTRACT_ANY); | | | |
109 | mutex_spin_enter(&rndpool_mtx); | | | |
110 | rnd_getmore(bytes - extracted); | | | |
111 | mutex_spin_exit(&rndpool_mtx); | | | |
112 | return false; | | | |
113 | } | | | |
114 | | | | |
115 | return true; | | | |
116 | } | | | |
117 | | | | |
118 | /* | | | |
119 | * If we have as much entropy as is requested, fill the buffer with it | | | |
120 | * and return true. Otherwise, leave the buffer alone and return | | | |
121 | * false. | | | |
122 | */ | | | |
123 | | | | |
124 | CTASSERT(RND_ENTROPY_THRESHOLD <= 0xffffffffUL); | | | |
125 | CTASSERT(RNDSINK_MAX_BYTES <= (0xffffffffUL - RND_ENTROPY_THRESHOLD)); | | | |
126 | CTASSERT((RNDSINK_MAX_BYTES + RND_ENTROPY_THRESHOLD) <= | | | |
127 | (0xffffffffUL / NBBY)); | | | |
128 | | | | |
129 | static bool | | | |
130 | rndpool_maybe_extract(void *buffer, size_t bytes) | | | |
131 | { | | | |
132 | bool ok; | | | |
133 | | | | |
134 | KASSERT(bytes <= RNDSINK_MAX_BYTES); | | | |
135 | | | | |
136 | const uint32_t bits_needed = ((bytes + RND_ENTROPY_THRESHOLD) * NBBY); | | | |
137 | | | | |
138 | mutex_spin_enter(&rndpool_mtx); | | | |
139 | if (bits_needed <= rndpool_get_entropy_count(&rnd_pool)) { | | | |
140 | const uint32_t extracted __diagused = | | | |
141 | rndpool_extract_data(&rnd_pool, buffer, bytes, | | | |
142 | RND_EXTRACT_GOOD); | | | |
143 | | | | |
144 | KASSERT(extracted == bytes); | | | |
145 | | | | |
146 | ok = true; | | | |
147 | } else { | | | |
148 | ok = false; | | | |
149 | rnd_getmore(howmany(bits_needed - | | | |
150 | rndpool_get_entropy_count(&rnd_pool), NBBY)); | | | |
151 | } | | | |
152 | mutex_spin_exit(&rndpool_mtx); | | | |
153 | | | | |
154 | return ok; | | | |
155 | } | | | |
156 | | | | |
157 | void | | 89 | void |
158 | rndsinks_distribute(void) | | 90 | rndsinks_distribute(void) |
159 | { | | 91 | { |
160 | uint8_t buffer[RNDSINK_MAX_BYTES]; | | 92 | uint8_t buffer[RNDSINK_MAX_BYTES]; |
161 | struct rndsink *rndsink; | | 93 | struct rndsink *rndsink; |
162 | | | 94 | |
163 | explicit_memset(buffer, 0, sizeof(buffer)); /* paranoia */ | | 95 | explicit_memset(buffer, 0, sizeof(buffer)); /* paranoia */ |
164 | | | 96 | |
165 | mutex_spin_enter(&rndsinks_lock); | | 97 | mutex_spin_enter(&rndsinks_lock); |
166 | while ((rndsink = TAILQ_FIRST(&rndsinks)) != NULL) { | | 98 | while ((rndsink = TAILQ_FIRST(&rndsinks)) != NULL) { |
167 | KASSERT(rndsink->rsink_state == RNDSINK_QUEUED); | | 99 | KASSERT(rndsink->rsink_state == RNDSINK_QUEUED); |
168 | | | 100 | |
169 | /* Bail if we can't get some entropy for this rndsink. */ | | 101 | /* Bail if we can't get some entropy for this rndsink. */ |
170 | if (!rndpool_maybe_extract(buffer, rndsink->rsink_bytes)) | | 102 | if (!rnd_tryextract(buffer, rndsink->rsink_bytes)) |
171 | break; | | 103 | break; |
172 | | | 104 | |
173 | /* | | 105 | /* |
174 | * Got some entropy. Take the sink off the queue and | | 106 | * Got some entropy. Take the sink off the queue and |
175 | * feed the entropy to the callback, with rndsinks_lock | | 107 | * feed the entropy to the callback, with rndsinks_lock |
176 | * dropped. While running the callback, lock out | | 108 | * dropped. While running the callback, lock out |
177 | * rndsink_destroy by marking the sink in flight. | | 109 | * rndsink_destroy by marking the sink in flight. |
178 | */ | | 110 | */ |
179 | TAILQ_REMOVE(&rndsinks, rndsink, rsink_entry); | | 111 | TAILQ_REMOVE(&rndsinks, rndsink, rsink_entry); |
180 | rndsink->rsink_state = RNDSINK_IN_FLIGHT; | | 112 | rndsink->rsink_state = RNDSINK_IN_FLIGHT; |
181 | mutex_spin_exit(&rndsinks_lock); | | 113 | mutex_spin_exit(&rndsinks_lock); |
182 | | | 114 | |
183 | (*rndsink->rsink_callback)(rndsink->rsink_arg, buffer, | | 115 | (*rndsink->rsink_callback)(rndsink->rsink_arg, buffer, |
| @@ -215,29 +147,32 @@ rndsinks_enqueue(struct rndsink *rndsink | | | @@ -215,29 +147,32 @@ rndsinks_enqueue(struct rndsink *rndsink |
215 | /* | | 147 | /* |
216 | * XXX This should request only rndsink->rs_bytes bytes of | | 148 | * XXX This should request only rndsink->rs_bytes bytes of |
217 | * entropy, but that might get buffered up indefinitely because | | 149 | * entropy, but that might get buffered up indefinitely because |
218 | * kern_rndq has no bound on the duration before it will | | 150 | * kern_rndq has no bound on the duration before it will |
219 | * process queued entropy samples. To work around this, we are | | 151 | * process queued entropy samples. To work around this, we are |
220 | * a little too incestuous with kern_rndq: we avoid marking polled | | 152 | * a little too incestuous with kern_rndq: we avoid marking polled |
221 | * sources "fast" there, and know here that for non-fast sources, | | 153 | * sources "fast" there, and know here that for non-fast sources, |
222 | * that code will buffer two ints worth of data per source. | | 154 | * that code will buffer two ints worth of data per source. |
223 | * Later, we ought to (a) bound the duration before | | 155 | * Later, we ought to (a) bound the duration before |
224 | * queued entropy samples get processed, and (b) add a target | | 156 | * queued entropy samples get processed, and (b) add a target |
225 | * or something -- as soon as we get that much from the entropy | | 157 | * or something -- as soon as we get that much from the entropy |
226 | * sources, distribute it. | | 158 | * sources, distribute it. |
227 | */ | | 159 | */ |
| | | 160 | { |
| | | 161 | extern kmutex_t rndpool_mtx; |
228 | mutex_spin_enter(&rndpool_mtx); | | 162 | mutex_spin_enter(&rndpool_mtx); |
229 | rnd_getmore(MAX(rndsink->rsink_bytes, 2 * sizeof(uint32_t))); | | 163 | rnd_getmore(MAX(rndsink->rsink_bytes, 2 * sizeof(uint32_t))); |
230 | mutex_spin_exit(&rndpool_mtx); | | 164 | mutex_spin_exit(&rndpool_mtx); |
| | | 165 | } |
231 | | | 166 | |
232 | switch (rndsink->rsink_state) { | | 167 | switch (rndsink->rsink_state) { |
233 | case RNDSINK_IDLE: | | 168 | case RNDSINK_IDLE: |
234 | /* Not on the queue and nobody is handling it. */ | | 169 | /* Not on the queue and nobody is handling it. */ |
235 | TAILQ_INSERT_TAIL(&rndsinks, rndsink, rsink_entry); | | 170 | TAILQ_INSERT_TAIL(&rndsinks, rndsink, rsink_entry); |
236 | rndsink->rsink_state = RNDSINK_QUEUED; | | 171 | rndsink->rsink_state = RNDSINK_QUEUED; |
237 | break; | | 172 | break; |
238 | | | 173 | |
239 | case RNDSINK_QUEUED: | | 174 | case RNDSINK_QUEUED: |
240 | /* Already on the queue. */ | | 175 | /* Already on the queue. */ |
241 | break; | | 176 | break; |
242 | | | 177 | |
243 | case RNDSINK_IN_FLIGHT: | | 178 | case RNDSINK_IN_FLIGHT: |
| @@ -321,20 +256,20 @@ rndsink_schedule(struct rndsink *rndsink | | | @@ -321,20 +256,20 @@ rndsink_schedule(struct rndsink *rndsink |
321 | mutex_spin_enter(&rndsinks_lock); | | 256 | mutex_spin_enter(&rndsinks_lock); |
322 | rndsinks_enqueue(rndsink); | | 257 | rndsinks_enqueue(rndsink); |
323 | mutex_spin_exit(&rndsinks_lock); | | 258 | mutex_spin_exit(&rndsinks_lock); |
324 | } | | 259 | } |
325 | } | | 260 | } |
326 | | | 261 | |
327 | bool | | 262 | bool |
328 | rndsink_request(struct rndsink *rndsink, void *buffer, size_t bytes) | | 263 | rndsink_request(struct rndsink *rndsink, void *buffer, size_t bytes) |
329 | { | | 264 | { |
330 | | | 265 | |
331 | KASSERT(bytes == rndsink->rsink_bytes); | | 266 | KASSERT(bytes == rndsink->rsink_bytes); |
332 | | | 267 | |
333 | mutex_spin_enter(&rndsinks_lock); | | 268 | mutex_spin_enter(&rndsinks_lock); |
334 | const bool full_entropy = rndpool_extract(buffer, bytes); | | 269 | const bool full_entropy = rnd_extract(buffer, bytes); |
335 | if (!full_entropy) | | 270 | if (!full_entropy) |
336 | rndsinks_enqueue(rndsink); | | 271 | rndsinks_enqueue(rndsink); |
337 | mutex_spin_exit(&rndsinks_lock); | | 272 | mutex_spin_exit(&rndsinks_lock); |
338 | | | 273 | |
339 | return full_entropy; | | 274 | return full_entropy; |
340 | } | | 275 | } |