Created
August 28, 2017 17:26
-
-
Save jasperla/e27541ab2f3ac5300627893610c3ae6b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* $OpenBSD$ */ | |
| /* | |
| * Copyright (c) 2017 Jasper Lievisse Adriaanse <jasper@openbsd.org> | |
| * Copyright (c) 2017 Aaron Bieber <abieber@openbsd.org> | |
| * Copyright (C) 2015 Sean Levy <attila@stalphonsos.com> | |
| * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org> | |
| * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> | |
| * | |
| * Permission to use, copy, modify, and distribute this software for any | |
| * purpose with or without fee is hereby granted, provided that the above | |
| * copyright notice and this permission notice appear in all copies. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| */ | |
| /* | |
| * Universal TRNG driver for a collection of TRNG devices: | |
| * - ChaosKey TRNG | |
| * http://altusmetrum.org/ChaosKey/ | |
| * - Alea II TRNG. Produces 100kbit/sec of entropy by black magic | |
| * http://www.araneus.fi/products/alea2/en/ | |
| */ | |
| #include <sys/param.h> | |
| #include <sys/systm.h> | |
| #include <sys/device.h> | |
| #include <sys/timeout.h> | |
| #include <dev/usb/usb.h> | |
| #include <dev/usb/usbdi.h> | |
| #include <dev/usb/usbdevs.h> | |
| #include <dev/rndvar.h> | |
| #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) | |
| #ifdef URNG_DEBUG | |
| #define DPRINTF(x) printf x | |
| #else | |
| #define DPRINTF(x) | |
| #endif | |
| struct urng_chip { | |
| int bufsiz; | |
| int endpoint; | |
| int iface; | |
| int msecs; | |
| int read_timeout; | |
| }; | |
| struct urng_softc { | |
| struct device sc_dev; | |
| struct usbd_device *sc_udev; | |
| struct usbd_pipe *sc_pipe; | |
| struct timeout sc_timeout; | |
| struct usb_task sc_task; | |
| struct usbd_xfer *sc_xfer; | |
| struct urng_chip sc_chip; | |
| int *sc_buf; | |
| }; | |
| int urng_match(struct device *, void *, void *); | |
| void urng_attach(struct device *, struct device *, void *); | |
| int urng_detach(struct device *, int); | |
| void urng_task(void *); | |
| void urng_timeout(void *); | |
| struct cfdriver urng_cd = { | |
| NULL, "urng", DV_DULL | |
| }; | |
| const struct cfattach urng_ca = { | |
| sizeof(struct urng_softc), urng_match, urng_attach, urng_detach | |
| }; | |
| struct urng_type { | |
| struct usb_devno urng_dev; | |
| struct urng_chip urng_chip; | |
| }; | |
| static const struct urng_type urng_devs[] = { | |
| { { USB_VENDOR_OPENMOKO2, USB_PRODUCT_OPENMOKO2_CHAOSKEY }, | |
| {64, 6, 0, 100, 5000} }, | |
| { { USB_VENDOR_ARANEUS, USB_PRODUCT_ARANEUS_ALEA }, | |
| {128, 1, 0, 100, 5000} }, | |
| }; | |
| #define urng_lookup(v, p) ((struct urng_type *)usb_lookup(urng_devs, v, p)) | |
| int | |
| urng_match(struct device *parent, void *match, void *aux) | |
| { | |
| struct usb_attach_arg *uaa = aux; | |
| if (uaa->iface == NULL) | |
| return (UMATCH_NONE); | |
| if (urng_lookup(uaa->vendor, uaa->product) != NULL) | |
| return (UMATCH_VENDOR_PRODUCT); | |
| return (UMATCH_NONE); | |
| } | |
| void | |
| urng_attach(struct device *parent, struct device *self, void *aux) | |
| { | |
| struct urng_softc *sc = (struct urng_softc *)self; | |
| struct usb_attach_arg *uaa = aux; | |
| usb_interface_descriptor_t *id; | |
| usb_endpoint_descriptor_t *ed; | |
| int ep_ibulk = -1; | |
| usbd_status error; | |
| int i; | |
| sc->sc_udev = uaa->device; | |
| sc->sc_chip = urng_lookup(uaa->vendor, uaa->product)->urng_chip; | |
| DPRINTF(("%s: bufsiz: %d, endpoint: %d iface: %d, msecs: %d, read_timeout: %d\n", | |
| DEVNAME(sc), | |
| sc->sc_chip.bufsiz, | |
| sc->sc_chip.endpoint, | |
| sc->sc_chip.iface, | |
| sc->sc_chip.msecs, | |
| sc->sc_chip.read_timeout)); | |
| id = usbd_get_interface_descriptor(uaa->iface); | |
| for (i = 0; i < id->bNumEndpoints; i++) { | |
| ed = usbd_interface2endpoint_descriptor(uaa->iface, i); | |
| if (ed == NULL) { | |
| printf("%s: failed to get endpoint %d descriptor\n", | |
| DEVNAME(sc), i); | |
| return; | |
| } | |
| if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
| UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK && | |
| UE_GET_ADDR(ed->bEndpointAddress) == sc->sc_chip.endpoint) { | |
| ep_ibulk = ed->bEndpointAddress; | |
| break; | |
| } | |
| } | |
| if (ep_ibulk == -1) { | |
| printf("%s: missing endpoint\n", DEVNAME(sc)); | |
| return; | |
| } | |
| error = usbd_open_pipe(uaa->iface, ep_ibulk, USBD_EXCLUSIVE_USE, | |
| &sc->sc_pipe); | |
| if (error) { | |
| printf("%s: failed to open bulk-in pipe: %s\n", | |
| DEVNAME(sc), usbd_errstr(error)); | |
| return; | |
| } | |
| sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev); | |
| if (sc->sc_xfer == NULL) { | |
| printf("%s: could not alloc xfer\n", DEVNAME(sc)); | |
| return; | |
| } | |
| sc->sc_buf = usbd_alloc_buffer(sc->sc_xfer, sc->sc_chip.bufsiz); | |
| if (sc->sc_buf == NULL) { | |
| printf("%s: could not alloc %d-byte buffer\n", DEVNAME(sc), | |
| sc->sc_chip.bufsiz); | |
| return; | |
| } | |
| usb_init_task(&sc->sc_task, urng_task, sc, USB_TASK_TYPE_GENERIC); | |
| timeout_set(&sc->sc_timeout, urng_timeout, sc); | |
| usb_add_task(sc->sc_udev, &sc->sc_task); | |
| return; | |
| } | |
| int | |
| urng_detach(struct device *self, int flags) | |
| { | |
| struct urng_softc *sc = (struct urng_softc *)self; | |
| usb_rem_task(sc->sc_udev, &sc->sc_task); | |
| if (timeout_initialized(&sc->sc_timeout)) | |
| timeout_del(&sc->sc_timeout); | |
| if (sc->sc_xfer) | |
| usbd_free_xfer(sc->sc_xfer); | |
| if (sc->sc_pipe != NULL) | |
| usbd_close_pipe(sc->sc_pipe); | |
| return (0); | |
| } | |
| void | |
| urng_task(void *arg) | |
| { | |
| struct urng_softc *sc = (struct urng_softc *)arg; | |
| usbd_status error; | |
| u_int32_t len, i; | |
| usbd_setup_xfer(sc->sc_xfer, sc->sc_pipe, NULL, sc->sc_buf, | |
| sc->sc_chip.bufsiz, USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS, | |
| sc->sc_chip.read_timeout, NULL); | |
| error = usbd_transfer(sc->sc_xfer); | |
| if (error) { | |
| printf("%s: xfer failed: %s\n", DEVNAME(sc), | |
| usbd_errstr(error)); | |
| goto bail; | |
| } | |
| usbd_get_xfer_status(sc->sc_xfer, NULL, NULL, &len, NULL); | |
| if (len < sizeof(int)) { | |
| printf("%s: xfer too short (%u bytes) - dropping\n", | |
| DEVNAME(sc), len); | |
| goto bail; | |
| } | |
| len /= sizeof(int); | |
| for (i = 0; i < len; i++) { | |
| add_true_randomness(sc->sc_buf[i]); | |
| } | |
| bail: | |
| timeout_add_msec(&sc->sc_timeout, sc->sc_chip.msecs); | |
| } | |
| void | |
| urng_timeout(void *arg) | |
| { | |
| struct urng_softc *sc = arg; | |
| usb_add_task(sc->sc_udev, &sc->sc_task); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment