LCOV - code coverage report
Current view: top level - dev/usb - urng.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 89 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.13