jcs's openbsd hax
openbsd
1/* $OpenBSD: urng.c,v 1.11 2024/05/23 03:21:09 jsg 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/timeout.h>
35
36#include <dev/usb/usb.h>
37#include <dev/usb/usbdi.h>
38#include <dev/usb/usbdevs.h>
39
40#define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
41
42#ifdef URNG_DEBUG
43#define DPRINTF(x) printf x
44#else
45#define DPRINTF(x)
46#endif
47
48/*
49 * Define URNG_MEASURE_RATE to periodically log rate at which we provide
50 * random data to the kernel.
51 */
52#ifdef URNG_MEASURE_RATE
53#define URNG_RATE_SECONDS 30
54#endif
55
56struct urng_chip {
57 int bufsiz;
58 int endpoint;
59 int ctl_iface_idx;
60 int msecs;
61 int read_timeout;
62};
63
64struct urng_softc {
65 struct device sc_dev;
66 struct usbd_device *sc_udev;
67 struct usbd_pipe *sc_inpipe;
68 struct timeout sc_timeout;
69 struct usb_task sc_task;
70 struct usbd_xfer *sc_xfer;
71 struct urng_chip sc_chip;
72 int *sc_buf;
73 int sc_product;
74#ifdef URNG_MEASURE_RATE
75 struct timeval sc_start;
76 struct timeval sc_cur;
77 int sc_counted_bytes;
78 u_char sc_first_run;
79#endif
80};
81
82int urng_match(struct device *, void *, void *);
83void urng_attach(struct device *, struct device *, void *);
84int urng_detach(struct device *, int);
85void urng_task(void *);
86void urng_timeout(void *);
87
88struct cfdriver urng_cd = {
89 NULL, "urng", DV_DULL
90};
91
92const struct cfattach urng_ca = {
93 sizeof(struct urng_softc), urng_match, urng_attach, urng_detach
94};
95
96struct urng_type {
97 struct usb_devno urng_dev;
98 struct urng_chip urng_chip;
99};
100
101static const struct urng_type urng_devs[] = {
102 { { USB_VENDOR_OPENMOKO2, USB_PRODUCT_OPENMOKO2_CHAOSKEY },
103 {64, 5, 0, 100, 5000} },
104 { { USB_VENDOR_ARANEUS, USB_PRODUCT_ARANEUS_ALEA },
105 {128, 1, 0, 100, 5000} },
106};
107#define urng_lookup(v, p) ((struct urng_type *)usb_lookup(urng_devs, v, p))
108
109int
110urng_match(struct device *parent, void *match, void *aux)
111{
112 struct usb_attach_arg *uaa = aux;
113
114 if (uaa->iface == NULL)
115 return (UMATCH_NONE);
116
117 if (urng_lookup(uaa->vendor, uaa->product) != NULL)
118 return (UMATCH_VENDOR_PRODUCT);
119
120 return (UMATCH_NONE);
121}
122
123void
124urng_attach(struct device *parent, struct device *self, void *aux)
125{
126 struct urng_softc *sc = (struct urng_softc *)self;
127 struct usb_attach_arg *uaa = aux;
128 usb_interface_descriptor_t *id;
129 usb_endpoint_descriptor_t *ed;
130 int ep_ibulk = -1;
131 usbd_status error;
132 int i, ep_addr;
133
134 sc->sc_udev = uaa->device;
135 sc->sc_chip = urng_lookup(uaa->vendor, uaa->product)->urng_chip;
136 sc->sc_product = uaa->product;
137#ifdef URNG_MEASURE_RATE
138 sc->sc_first_run = 1;
139#endif
140
141 DPRINTF(("%s: bufsiz: %d, endpoint: %d ctl iface: %d, msecs: %d, read_timeout: %d\n",
142 DEVNAME(sc),
143 sc->sc_chip.bufsiz,
144 sc->sc_chip.endpoint,
145 sc->sc_chip.ctl_iface_idx,
146 sc->sc_chip.msecs,
147 sc->sc_chip.read_timeout));
148
149 /* Find the bulk endpoints. */
150 id = usbd_get_interface_descriptor(uaa->iface);
151 for (i = 0; i < id->bNumEndpoints; i++) {
152 ed = usbd_interface2endpoint_descriptor(uaa->iface, i);
153 if (ed == NULL) {
154 printf("%s: failed to get endpoint %d descriptor\n",
155 DEVNAME(sc), i);
156 goto fail;
157 }
158 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
159 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
160 ep_addr = UE_GET_ADDR(ed->bEndpointAddress);
161
162 DPRINTF(("%s: bulk endpoint %d\n",
163 DEVNAME(sc), ep_addr));
164
165 if (ep_addr == sc->sc_chip.endpoint) {
166 ep_ibulk = ed->bEndpointAddress;
167 break;
168 }
169 }
170 }
171
172 if (ep_ibulk == -1) {
173 printf("%s: missing bulk input endpoint\n", DEVNAME(sc));
174 goto fail;
175 }
176
177 /* Open the pipes. */
178 error = usbd_open_pipe(uaa->iface, ep_ibulk, USBD_EXCLUSIVE_USE,
179 &sc->sc_inpipe);
180 if (error) {
181 printf("%s: failed to open bulk-in pipe: %s\n",
182 DEVNAME(sc), usbd_errstr(error));
183 goto fail;
184 }
185
186 /* Allocate the transfer buffers. */
187 sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev);
188 if (sc->sc_xfer == NULL) {
189 printf("%s: could not alloc xfer\n", DEVNAME(sc));
190 goto fail;
191 }
192
193 sc->sc_buf = usbd_alloc_buffer(sc->sc_xfer, sc->sc_chip.bufsiz);
194 if (sc->sc_buf == NULL) {
195 printf("%s: could not alloc %d-byte buffer\n", DEVNAME(sc),
196 sc->sc_chip.bufsiz);
197 goto fail;
198 }
199
200 /* And off we go! */
201 usb_init_task(&sc->sc_task, urng_task, sc, USB_TASK_TYPE_GENERIC);
202 timeout_set(&sc->sc_timeout, urng_timeout, sc);
203 usb_add_task(sc->sc_udev, &sc->sc_task);
204
205 return;
206
207fail:
208 usbd_deactivate(sc->sc_udev);
209}
210
211int
212urng_detach(struct device *self, int flags)
213{
214 struct urng_softc *sc = (struct urng_softc *)self;
215
216 usb_rem_task(sc->sc_udev, &sc->sc_task);
217
218 if (timeout_initialized(&sc->sc_timeout))
219 timeout_del(&sc->sc_timeout);
220
221 if (sc->sc_xfer != NULL) {
222 usbd_free_xfer(sc->sc_xfer);
223 sc->sc_xfer = NULL;
224 }
225
226 if (sc->sc_inpipe != NULL) {
227 usbd_close_pipe(sc->sc_inpipe);
228 sc->sc_inpipe = NULL;
229 }
230
231 return (0);
232}
233
234
235void
236urng_task(void *arg)
237{
238 struct urng_softc *sc = (struct urng_softc *)arg;
239 usbd_status error;
240 u_int32_t len, i;
241#ifdef URNG_MEASURE_RATE
242 time_t elapsed;
243 int rate;
244#endif
245 usbd_setup_xfer(sc->sc_xfer, sc->sc_inpipe, NULL, sc->sc_buf,
246 sc->sc_chip.bufsiz, USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS,
247 sc->sc_chip.read_timeout, NULL);
248
249 error = usbd_transfer(sc->sc_xfer);
250 if (error) {
251 printf("%s: xfer failed: %s\n", DEVNAME(sc),
252 usbd_errstr(error));
253 goto bail;
254 }
255
256 usbd_get_xfer_status(sc->sc_xfer, NULL, NULL, &len, NULL);
257 if (len < sizeof(int)) {
258 printf("%s: xfer too short (%u bytes) - dropping\n",
259 DEVNAME(sc), len);
260 goto bail;
261 }
262
263#ifdef URNG_MEASURE_RATE
264 if (sc->sc_first_run) {
265 sc->sc_counted_bytes = 0;
266 getmicrotime(&(sc->sc_start));
267 }
268 sc->sc_counted_bytes += len;
269 getmicrotime(&(sc->sc_cur));
270 elapsed = sc->sc_cur.tv_sec - sc->sc_start.tv_sec;
271 if (elapsed >= URNG_RATE_SECONDS) {
272 rate = (8 * sc->sc_counted_bytes) / (elapsed * 1024);
273 printf("%s: transfer rate = %d kb/s\n", DEVNAME(sc), rate);
274
275 /* set up for next measurement */
276 sc->sc_counted_bytes = 0;
277 getmicrotime(&(sc->sc_start));
278 }
279#endif
280
281 len /= sizeof(int);
282 for (i = 0; i < len; i++) {
283 enqueue_randomness(sc->sc_buf[i]);
284 }
285bail:
286#ifdef URNG_MEASURE_RATE
287 if (sc->sc_first_run) {
288 sc->sc_first_run = 0;
289 }
290#endif
291
292 timeout_add_msec(&sc->sc_timeout, sc->sc_chip.msecs);
293}
294
295void
296urng_timeout(void *arg)
297{
298 struct urng_softc *sc = arg;
299
300 usb_add_task(sc->sc_udev, &sc->sc_task);
301}