Line data Source code
1 : /* $OpenBSD: urng.c,v 1.9 2018/07/09 20:09:00 jasper Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2017 Jasper Lievisse Adriaanse <jasper@openbsd.org>
5 : * Copyright (c) 2017 Aaron Bieber <abieber@openbsd.org>
6 : * Copyright (C) 2015 Sean Levy <attila@stalphonsos.com>
7 : * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org>
8 : * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
9 : *
10 : * Permission to use, copy, modify, and distribute this software for any
11 : * purpose with or without fee is hereby granted, provided that the above
12 : * copyright notice and this permission notice appear in all copies.
13 : *
14 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 : */
22 :
23 : /*
24 : * Universal TRNG driver for a collection of TRNG devices:
25 : * - ChaosKey TRNG
26 : * http://altusmetrum.org/ChaosKey/
27 : * - Alea II TRNG. Produces 100kbit/sec of entropy by black magic
28 : * http://www.araneus.fi/products/alea2/en/
29 : */
30 :
31 : #include <sys/param.h>
32 : #include <sys/systm.h>
33 : #include <sys/device.h>
34 : #include <sys/time.h>
35 : #include <sys/timeout.h>
36 :
37 : #include <dev/usb/usb.h>
38 : #include <dev/usb/usbdi.h>
39 : #include <dev/usb/usbdevs.h>
40 :
41 : #include <dev/rndvar.h>
42 :
43 : #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
44 :
45 : #ifdef URNG_DEBUG
46 : #define DPRINTF(x) printf x
47 : #else
48 : #define DPRINTF(x)
49 : #endif
50 :
51 : /*
52 : * Define URNG_MEASURE_RATE to periodically log rate at which we provide
53 : * random data to the kernel.
54 : */
55 : #ifdef URNG_MEASURE_RATE
56 : #define URNG_RATE_SECONDS 30
57 : #endif
58 :
59 : struct urng_chip {
60 : int bufsiz;
61 : int endpoint;
62 : int ctl_iface_idx;
63 : int msecs;
64 : int read_timeout;
65 : };
66 :
67 : struct urng_softc {
68 : struct device sc_dev;
69 : struct usbd_device *sc_udev;
70 : struct usbd_pipe *sc_inpipe;
71 : struct timeout sc_timeout;
72 : struct usb_task sc_task;
73 : struct usbd_xfer *sc_xfer;
74 : struct urng_chip sc_chip;
75 : int *sc_buf;
76 : int sc_product;
77 : #ifdef URNG_MEASURE_RATE
78 : struct timeval sc_start;
79 : struct timeval sc_cur;
80 : int sc_counted_bytes;
81 : u_char sc_first_run;
82 : #endif
83 : };
84 :
85 : int urng_match(struct device *, void *, void *);
86 : void urng_attach(struct device *, struct device *, void *);
87 : int urng_detach(struct device *, int);
88 : void urng_task(void *);
89 : void urng_timeout(void *);
90 :
91 : struct cfdriver urng_cd = {
92 : NULL, "urng", DV_DULL
93 : };
94 :
95 : const struct cfattach urng_ca = {
96 : sizeof(struct urng_softc), urng_match, urng_attach, urng_detach
97 : };
98 :
99 : struct urng_type {
100 : struct usb_devno urng_dev;
101 : struct urng_chip urng_chip;
102 : };
103 :
104 : static const struct urng_type urng_devs[] = {
105 : { { USB_VENDOR_OPENMOKO2, USB_PRODUCT_OPENMOKO2_CHAOSKEY },
106 : {64, 5, 0, 100, 5000} },
107 : { { USB_VENDOR_ARANEUS, USB_PRODUCT_ARANEUS_ALEA },
108 : {128, 1, 0, 100, 5000} },
109 : };
110 : #define urng_lookup(v, p) ((struct urng_type *)usb_lookup(urng_devs, v, p))
111 :
112 : int
113 0 : urng_match(struct device *parent, void *match, void *aux)
114 : {
115 0 : struct usb_attach_arg *uaa = aux;
116 :
117 0 : if (uaa->iface == NULL)
118 0 : return (UMATCH_NONE);
119 :
120 0 : if (urng_lookup(uaa->vendor, uaa->product) != NULL)
121 0 : return (UMATCH_VENDOR_PRODUCT);
122 :
123 0 : return (UMATCH_NONE);
124 0 : }
125 :
126 : void
127 0 : urng_attach(struct device *parent, struct device *self, void *aux)
128 : {
129 0 : struct urng_softc *sc = (struct urng_softc *)self;
130 0 : struct usb_attach_arg *uaa = aux;
131 : usb_interface_descriptor_t *id;
132 : usb_endpoint_descriptor_t *ed;
133 : int ep_ibulk = -1;
134 : usbd_status error;
135 : int i, ep_addr;
136 :
137 0 : sc->sc_udev = uaa->device;
138 0 : sc->sc_chip = urng_lookup(uaa->vendor, uaa->product)->urng_chip;
139 0 : sc->sc_product = uaa->product;
140 : #ifdef URNG_MEASURE_RATE
141 : sc->sc_first_run = 1;
142 : #endif
143 :
144 : DPRINTF(("%s: bufsiz: %d, endpoint: %d ctl iface: %d, msecs: %d, read_timeout: %d\n",
145 : DEVNAME(sc),
146 : sc->sc_chip.bufsiz,
147 : sc->sc_chip.endpoint,
148 : sc->sc_chip.ctl_iface_idx,
149 : sc->sc_chip.msecs,
150 : sc->sc_chip.read_timeout));
151 :
152 : /* Find the bulk endpoints. */
153 0 : id = usbd_get_interface_descriptor(uaa->iface);
154 0 : for (i = 0; i < id->bNumEndpoints; i++) {
155 0 : ed = usbd_interface2endpoint_descriptor(uaa->iface, i);
156 0 : if (ed == NULL) {
157 0 : printf("%s: failed to get endpoint %d descriptor\n",
158 0 : DEVNAME(sc), i);
159 0 : goto fail;
160 : }
161 0 : if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
162 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
163 0 : ep_addr = UE_GET_ADDR(ed->bEndpointAddress);
164 :
165 : DPRINTF(("%s: bulk endpoint %d\n",
166 : DEVNAME(sc), ep_addr));
167 :
168 0 : if (ep_addr == sc->sc_chip.endpoint) {
169 : ep_ibulk = ed->bEndpointAddress;
170 0 : break;
171 : }
172 : }
173 : }
174 :
175 0 : if (ep_ibulk == -1) {
176 0 : printf("%s: missing bulk input endpoint\n", DEVNAME(sc));
177 0 : goto fail;
178 : }
179 :
180 : /* Open the pipes. */
181 0 : error = usbd_open_pipe(uaa->iface, ep_ibulk, USBD_EXCLUSIVE_USE,
182 0 : &sc->sc_inpipe);
183 0 : if (error) {
184 0 : printf("%s: failed to open bulk-in pipe: %s\n",
185 0 : DEVNAME(sc), usbd_errstr(error));
186 0 : goto fail;
187 : }
188 :
189 : /* Allocate the transfer buffers. */
190 0 : sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev);
191 0 : if (sc->sc_xfer == NULL) {
192 0 : printf("%s: could not alloc xfer\n", DEVNAME(sc));
193 0 : goto fail;
194 : }
195 :
196 0 : sc->sc_buf = usbd_alloc_buffer(sc->sc_xfer, sc->sc_chip.bufsiz);
197 0 : if (sc->sc_buf == NULL) {
198 0 : printf("%s: could not alloc %d-byte buffer\n", DEVNAME(sc),
199 0 : sc->sc_chip.bufsiz);
200 0 : goto fail;
201 : }
202 :
203 : /* And off we go! */
204 0 : usb_init_task(&sc->sc_task, urng_task, sc, USB_TASK_TYPE_GENERIC);
205 0 : timeout_set(&sc->sc_timeout, urng_timeout, sc);
206 0 : usb_add_task(sc->sc_udev, &sc->sc_task);
207 :
208 0 : return;
209 :
210 : fail:
211 0 : usbd_deactivate(sc->sc_udev);
212 0 : }
213 :
214 : int
215 0 : urng_detach(struct device *self, int flags)
216 : {
217 0 : struct urng_softc *sc = (struct urng_softc *)self;
218 :
219 0 : usb_rem_task(sc->sc_udev, &sc->sc_task);
220 :
221 0 : if (timeout_initialized(&sc->sc_timeout))
222 0 : timeout_del(&sc->sc_timeout);
223 :
224 0 : if (sc->sc_xfer != NULL) {
225 0 : usbd_free_xfer(sc->sc_xfer);
226 0 : sc->sc_xfer = NULL;
227 0 : }
228 :
229 0 : if (sc->sc_inpipe != NULL) {
230 0 : usbd_close_pipe(sc->sc_inpipe);
231 0 : sc->sc_inpipe = NULL;
232 0 : }
233 :
234 0 : return (0);
235 : }
236 :
237 :
238 : void
239 0 : urng_task(void *arg)
240 : {
241 0 : struct urng_softc *sc = (struct urng_softc *)arg;
242 : usbd_status error;
243 0 : u_int32_t len, i;
244 : #ifdef URNG_MEASURE_RATE
245 : time_t elapsed;
246 : int rate;
247 : #endif
248 0 : usbd_setup_xfer(sc->sc_xfer, sc->sc_inpipe, NULL, sc->sc_buf,
249 0 : sc->sc_chip.bufsiz, USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS,
250 0 : sc->sc_chip.read_timeout, NULL);
251 :
252 0 : error = usbd_transfer(sc->sc_xfer);
253 0 : if (error) {
254 0 : printf("%s: xfer failed: %s\n", DEVNAME(sc),
255 0 : usbd_errstr(error));
256 0 : goto bail;
257 : }
258 :
259 0 : usbd_get_xfer_status(sc->sc_xfer, NULL, NULL, &len, NULL);
260 0 : if (len < sizeof(int)) {
261 0 : printf("%s: xfer too short (%u bytes) - dropping\n",
262 0 : DEVNAME(sc), len);
263 0 : goto bail;
264 : }
265 :
266 : #ifdef URNG_MEASURE_RATE
267 : if (sc->sc_first_run) {
268 : sc->sc_counted_bytes = 0;
269 : getmicrotime(&(sc->sc_start));
270 : }
271 : sc->sc_counted_bytes += len;
272 : getmicrotime(&(sc->sc_cur));
273 : elapsed = sc->sc_cur.tv_sec - sc->sc_start.tv_sec;
274 : if (elapsed >= URNG_RATE_SECONDS) {
275 : rate = (8 * sc->sc_counted_bytes) / (elapsed * 1024);
276 : printf("%s: transfer rate = %d kb/s\n", DEVNAME(sc), rate);
277 :
278 : /* set up for next measurement */
279 : sc->sc_counted_bytes = 0;
280 : getmicrotime(&(sc->sc_start));
281 : }
282 : #endif
283 :
284 0 : len /= sizeof(int);
285 0 : for (i = 0; i < len; i++) {
286 0 : enqueue_randomness(sc->sc_buf[i]);
287 : }
288 : bail:
289 : #ifdef URNG_MEASURE_RATE
290 : if (sc->sc_first_run) {
291 : sc->sc_first_run = 0;
292 : }
293 : #endif
294 :
295 0 : timeout_add_msec(&sc->sc_timeout, sc->sc_chip.msecs);
296 0 : }
297 :
298 : void
299 0 : urng_timeout(void *arg)
300 : {
301 0 : struct urng_softc *sc = arg;
302 :
303 0 : usb_add_task(sc->sc_udev, &sc->sc_task);
304 0 : }
|