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

          Line data    Source code
       1             : /*      $OpenBSD: uonerng.c,v 1.4 2018/07/09 20:06:12 jasper Exp $ */
       2             : /*
       3             :  * Copyright (C) 2015 Devin Reade <gdr@gno.org>
       4             :  * Copyright (C) 2015 Sean Levy <attila@stalphonsos.com>
       5             :  * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org>
       6             :  * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
       7             :  * Copyright (c) 1998 The NetBSD Foundation, Inc.
       8             :  *
       9             :  * Permission to use, copy, modify, and distribute this software for any
      10             :  * purpose with or without fee is hereby granted, provided that the above
      11             :  * copyright notice and this permission notice appear in all copies.
      12             :  *
      13             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      14             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      15             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      16             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      17             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      18             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      19             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      20             :  */
      21             : 
      22             : /*
      23             :  * Moonbase Otago OneRNG TRNG.  Note that the encoded vendor for this
      24             :  * device is OpenMoko as OpenMoko has made its device ranges available
      25             :  * for other open source / open hardware vendors.
      26             :  *
      27             :  * Product information can be found here:
      28             :  *     http://onerng.info/onerng
      29             :  *
      30             :  * Based on the ualea(4), uow(4), and umodem(4) source code.
      31             :  */
      32             : 
      33             : #include <sys/param.h>
      34             : #include <sys/systm.h>
      35             : #include <sys/device.h>
      36             : #include <sys/time.h>
      37             : #include <sys/timeout.h>
      38             : #include <machine/bus.h>
      39             : 
      40             : #include <dev/usb/usb.h>
      41             : #include <dev/usb/usbdi.h>
      42             : #include <dev/usb/usbdivar.h>
      43             : #include <dev/usb/usbdi_util.h>
      44             : #include <dev/usb/usbdevs.h>
      45             : #include <dev/usb/usbcdc.h>
      46             : 
      47             : #include <dev/rndvar.h>
      48             : 
      49             : /*
      50             :  * The OneRNG is documented to provide ~350kbits/s of entropy at
      51             :  * ~7.8 bits/byte, and when used at a lower rate providing close
      52             :  * to 8 bits/byte.
      53             :  *
      54             :  * Although this driver is able to consume the data at the full rate,
      55             :  * we tune this down to 10kbit/s as the OpenBSD RNG is better off
      56             :  * with small amounts of input at a time so as to not saturate the
      57             :  * input queue and mute other sources of entropy.
      58             :  *
      59             :  * Furthermore, unlike other implementations, for us there is no benefit
      60             :  * to discarding the initial bytes retrieved from the OneRNG, regardless
      61             :  * of the quality of the data. (Empirical tests suggest that the initial
      62             :  * quality is fine, anyway.)
      63             :  */
      64             : #define ONERNG_BUFSIZ           128
      65             : #define ONERNG_MSECS            100
      66             : 
      67             : #define ONERNG_TIMEOUT          1000    /* ms */
      68             : 
      69             : /*
      70             :  * Define ONERNG_MEASURE_RATE to periodically log rate at which we provide
      71             :  * random data to the kernel.
      72             :  */
      73             : #ifdef ONERNG_MEASURE_RATE
      74             : #define ONERNG_RATE_SECONDS 30
      75             : #endif
      76             : 
      77             : /* OneRNG operational modes */
      78             : #define ONERNG_OP_ENABLE        "cmdO\n" /* start emitting data */
      79             : #define ONERNG_OP_DISABLE       "cmdo\n" /* stop emitting data */
      80             : #define ONERNG_OP_FLUSH_ENTROPY "cmdw\n"
      81             : 
      82             : /* permits extracting the firmware in order to check the crypto signature */
      83             : #define ONERNG_OP_EXTRACT_FIRMWARE "cmdX\n"
      84             : 
      85             : /*
      86             :  * Noise sources include an avalache circuit and an RF circuit.
      87             :  * There is also a whitener to provide a uniform distribution.
      88             :  * Different combinations are possible.
      89             :  */
      90             : #define ONERNG_AVALANCHE_WHITENER       "cmd0\n" /* device default */
      91             : #define ONERNG_AVALANCHE                "cmd1\n"
      92             : #define ONERNG_AVALANCHE_RF_WHITENER    "cmd2\n"
      93             : #define ONERNG_AVALANCHE_RF             "cmd3\n"
      94             : #define ONERNG_SILENT                   "cmd4\n" /* none; necessary for cmdX */
      95             : #define ONERNG_SILENT2                  "cmd5\n"
      96             : #define ONERNG_RF_WHITENER              "cmd6\n"
      97             : #define ONERNG_RF                       "cmd7\n"
      98             : 
      99             : 
     100             : #define ONERNG_IFACE_CTRL_INDEX 0
     101             : #define ONERNG_IFACE_DATA_INDEX 1
     102             : 
     103             : #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
     104             : 
     105             : struct uonerng_softc {
     106             :         struct    device sc_dev;
     107             :         struct    usbd_device *sc_udev;
     108             : 
     109             :         int       sc_ctl_iface_no;                      /* control */
     110             :         struct    usbd_interface *sc_data_iface;        /* data */
     111             : 
     112             :         struct    usbd_pipe *sc_inpipe;
     113             :         struct    usbd_pipe *sc_outpipe;
     114             : 
     115             :         struct    timeout sc_timeout;
     116             :         struct    usb_task sc_task;
     117             :         struct    usbd_xfer *sc_xfer;
     118             :         int      *sc_buf;
     119             : #ifdef ONERNG_MEASURE_RATE
     120             :         struct    timeval sc_start;
     121             :         struct    timeval sc_cur;
     122             :         int       sc_counted_bytes;
     123             : #endif
     124             :         u_char    sc_dtr;                       /* current DTR state */
     125             :         u_char    sc_rts;                       /* current RTS state */
     126             :         u_char    sc_first_run;
     127             : };
     128             : 
     129             : int uonerng_match(struct device *, void *, void *);
     130             : void uonerng_attach(struct device *, struct device *, void *);
     131             : int uonerng_detach(struct device *, int);
     132             : void uonerng_task(void *);
     133             : void uonerng_timeout(void *);
     134             : int uonerng_enable(struct uonerng_softc *sc);
     135             : void uonerng_cleanup(struct uonerng_softc *sc);
     136             : usbd_status uonerng_set_line_state(struct uonerng_softc *sc);
     137             : usbd_status uonerng_rts(struct uonerng_softc *sc, int onoff);
     138             : 
     139             : struct cfdriver uonerng_cd = {
     140             :         NULL, "uonerng", DV_DULL
     141             : };
     142             : 
     143             : const struct cfattach uonerng_ca = {
     144             :         sizeof(struct uonerng_softc), uonerng_match, uonerng_attach, uonerng_detach
     145             : };
     146             : 
     147             : int
     148           0 : uonerng_match(struct device *parent, void *match, void *aux)
     149             : {
     150           0 :         struct usb_attach_arg *uaa = aux;
     151             : 
     152           0 :         if (uaa->iface == NULL)
     153           0 :                 return UMATCH_NONE;
     154             : 
     155           0 :         if (uaa->vendor != USB_VENDOR_OPENMOKO2 ||
     156           0 :             uaa->product != USB_PRODUCT_OPENMOKO2_ONERNG)
     157           0 :                 return UMATCH_NONE;
     158             : 
     159           0 :         return UMATCH_VENDOR_PRODUCT;
     160           0 : }
     161             : 
     162             : void
     163           0 : uonerng_attach(struct device *parent, struct device *self, void *aux)
     164             : {
     165           0 :         struct uonerng_softc *sc = (struct uonerng_softc *)self;
     166           0 :         struct usb_attach_arg *uaa = aux;
     167           0 :         struct usbd_interface *iface = uaa->iface;
     168             :         usb_interface_descriptor_t *id;
     169             :         usb_endpoint_descriptor_t *ed;
     170             :         int ep_ibulk = -1, ep_obulk = -1;
     171             :         usbd_status err;
     172             :         int i;
     173             : 
     174           0 :         sc->sc_udev = uaa->device;
     175           0 :         sc->sc_dtr = -1;
     176           0 :         sc->sc_rts = -1;
     177           0 :         sc->sc_first_run = 1;
     178             : 
     179           0 :         usb_init_task(&sc->sc_task, uonerng_task, sc, USB_TASK_TYPE_GENERIC);
     180             : 
     181             :         /* locate the control interface number and the data interface */
     182           0 :         err = usbd_device2interface_handle(sc->sc_udev,
     183             :             ONERNG_IFACE_CTRL_INDEX, &iface);
     184           0 :         if (err || iface == NULL) {
     185           0 :                 printf("%s: failed to locate control interface, err=%s\n",
     186           0 :                     DEVNAME(sc), usbd_errstr(err));
     187           0 :                 goto fail;
     188             :         }
     189           0 :         id = usbd_get_interface_descriptor(iface);
     190           0 :         if (id != NULL &&
     191           0 :             id->bInterfaceClass == UICLASS_CDC &&
     192           0 :             id->bInterfaceSubClass == UISUBCLASS_ABSTRACT_CONTROL_MODEL &&
     193           0 :             id->bInterfaceProtocol == UIPROTO_CDC_AT) {
     194           0 :                 sc->sc_ctl_iface_no = id->bInterfaceNumber;
     195             :         } else {
     196           0 :                 printf("%s: control interface number not found\n",
     197           0 :                     DEVNAME(sc));
     198           0 :                 goto fail;
     199             :         }
     200             : 
     201           0 :         err = usbd_device2interface_handle(sc->sc_udev,
     202           0 :             ONERNG_IFACE_DATA_INDEX, &sc->sc_data_iface);
     203           0 :         if (err || sc->sc_data_iface == NULL) {
     204           0 :                 printf("%s: failed to locate data interface, err=%s\n",
     205           0 :                     DEVNAME(sc), usbd_errstr(err));
     206           0 :                 goto fail;
     207             :         }
     208             : 
     209             :         /* Find the bulk endpoints */
     210           0 :         id = usbd_get_interface_descriptor(sc->sc_data_iface);
     211           0 :         if (id == NULL ||
     212           0 :             id->bInterfaceClass != UICLASS_CDC_DATA ||
     213           0 :             id->bInterfaceSubClass != UISUBCLASS_DATA) {
     214           0 :                 printf("%s: no data interface descriptor\n", DEVNAME(sc));
     215           0 :                 goto fail;
     216             :         }
     217           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     218           0 :                 ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i);
     219           0 :                 if (ed == NULL) {
     220           0 :                         printf("%s: no endpoint descriptor for %d\n",
     221           0 :                             DEVNAME(sc), i);
     222           0 :                         goto fail;
     223             :                 }
     224           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     225           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     226             :                         ep_ibulk = ed->bEndpointAddress;
     227           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
     228           0 :                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     229             :                         ep_obulk = ed->bEndpointAddress;
     230           0 :                 }
     231             :         }
     232             : 
     233           0 :         if (ep_ibulk == -1) {
     234           0 :                 printf("%s: Could not find data bulk in\n", DEVNAME(sc));
     235           0 :                 goto fail;
     236             :         }
     237           0 :         if (ep_obulk == -1) {
     238           0 :                 printf("%s: Could not find data bulk out\n", DEVNAME(sc));
     239           0 :                 goto fail;
     240             :         }
     241             : 
     242             :         /* Open pipes */
     243           0 :         err = usbd_open_pipe(sc->sc_data_iface, ep_ibulk,
     244           0 :             USBD_EXCLUSIVE_USE, &sc->sc_inpipe);
     245           0 :         if (err) {
     246           0 :                 printf("%s: failed to open bulk-in pipe: %s\n",
     247           0 :                     DEVNAME(sc), usbd_errstr(err));
     248           0 :                 goto fail;
     249             :         }
     250           0 :         err = usbd_open_pipe(sc->sc_data_iface, ep_obulk,
     251           0 :             USBD_EXCLUSIVE_USE, &sc->sc_outpipe);
     252           0 :         if (err) {
     253           0 :                 printf("%s: failed to open bulk-out pipe: %s\n",
     254           0 :                     DEVNAME(sc), usbd_errstr(err));
     255           0 :                 goto fail;
     256             :         }
     257             : 
     258             :         /* Allocate xfer/buffer for bulk transfers */
     259           0 :         sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev);
     260           0 :         if (sc->sc_xfer == NULL) {
     261           0 :                 printf("%s: could not alloc xfer\n", DEVNAME(sc));
     262           0 :                 goto fail;
     263             :         }
     264           0 :         sc->sc_buf = usbd_alloc_buffer(sc->sc_xfer, ONERNG_BUFSIZ);
     265           0 :         if (sc->sc_buf == NULL) {
     266           0 :                 printf("%s: could not alloc %d-byte buffer\n", DEVNAME(sc),
     267             :                     ONERNG_BUFSIZ);
     268           0 :                 goto fail;
     269             :         }
     270             : 
     271           0 :         if (uonerng_enable(sc) != 0) {
     272             :                 goto fail;
     273             :         }
     274             : 
     275           0 :         timeout_set(&sc->sc_timeout, uonerng_timeout, sc);
     276             : 
     277             :         /* get the initial random data as early as possible */
     278           0 :         uonerng_task(sc);
     279             : 
     280           0 :         usb_add_task(sc->sc_udev, &sc->sc_task);
     281           0 :         return;
     282             : 
     283             :  fail:
     284           0 :         usbd_deactivate(sc->sc_udev);
     285           0 :         uonerng_cleanup(sc);
     286           0 : }
     287             : 
     288             : int
     289           0 : uonerng_enable(struct uonerng_softc *sc)
     290             : {
     291             :         int err;
     292             : 
     293           0 :         if ((err = uonerng_rts(sc, 0))) {
     294           0 :                 printf("%s: failed to clear RTS: %s\n", DEVNAME(sc),
     295           0 :                     usbd_errstr(err));
     296           0 :                 return (1);
     297             :         }
     298             : 
     299           0 :         usbd_setup_xfer(sc->sc_xfer, sc->sc_outpipe, sc,
     300             :             ONERNG_AVALANCHE_WHITENER, sizeof(ONERNG_AVALANCHE_WHITENER),
     301             :             USBD_SYNCHRONOUS, ONERNG_TIMEOUT, NULL);
     302           0 :         if ((err = usbd_transfer(sc->sc_xfer))) {
     303           0 :                 printf("%s: failed to set operating mode: %s\n",
     304           0 :                     DEVNAME(sc), usbd_errstr(err));
     305           0 :                 return (1);
     306             :         }
     307             : 
     308           0 :         usbd_setup_xfer(sc->sc_xfer, sc->sc_outpipe, sc,
     309             :             ONERNG_OP_ENABLE, sizeof(ONERNG_OP_ENABLE),
     310             :             USBD_SYNCHRONOUS, ONERNG_TIMEOUT, NULL);
     311           0 :         if ((err = usbd_transfer(sc->sc_xfer))) {
     312           0 :                 printf("%s: failed to enable device: %s\n",
     313           0 :                     DEVNAME(sc), usbd_errstr(err));
     314           0 :                 return (1);
     315             :         }
     316             : 
     317           0 :         return (0);
     318           0 : }
     319             : 
     320             : int
     321           0 : uonerng_detach(struct device *self, int flags)
     322             : {
     323           0 :         struct uonerng_softc *sc = (struct uonerng_softc *)self;
     324             : 
     325           0 :         usb_rem_task(sc->sc_udev, &sc->sc_task);
     326           0 :         if (timeout_initialized(&sc->sc_timeout)) {
     327           0 :                 timeout_del(&sc->sc_timeout);
     328           0 :         }
     329           0 :         uonerng_cleanup(sc);
     330           0 :         return (0);
     331             : }
     332             : 
     333             : void
     334           0 : uonerng_cleanup(struct uonerng_softc *sc)
     335             : {
     336           0 :         if (sc->sc_inpipe != NULL) {
     337           0 :                 usbd_close_pipe(sc->sc_inpipe);
     338           0 :                 sc->sc_inpipe = NULL;
     339           0 :         }
     340           0 :         if (sc->sc_outpipe != NULL) {
     341           0 :                 usbd_close_pipe(sc->sc_outpipe);
     342           0 :                 sc->sc_outpipe = NULL;
     343           0 :         }
     344             : 
     345             :         /* usbd_free_xfer will also free the buffer if necessary */
     346           0 :         if (sc->sc_xfer != NULL) {
     347           0 :                 usbd_free_xfer(sc->sc_xfer);
     348           0 :                 sc->sc_xfer = NULL;
     349           0 :         }
     350           0 : }
     351             : 
     352             : usbd_status
     353           0 : uonerng_rts(struct uonerng_softc *sc, int onoff)
     354             : {
     355           0 :         if (sc->sc_rts == onoff)
     356           0 :                 return USBD_NORMAL_COMPLETION;
     357           0 :         sc->sc_rts = onoff;
     358             : 
     359           0 :         return uonerng_set_line_state(sc);
     360           0 : }
     361             : 
     362             : usbd_status
     363           0 : uonerng_set_line_state(struct uonerng_softc *sc)
     364             : {
     365           0 :         usb_device_request_t req;
     366             :         int ls;
     367             : 
     368           0 :         ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) |
     369           0 :              (sc->sc_rts ? UCDC_LINE_RTS : 0);
     370           0 :         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
     371           0 :         req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
     372           0 :         USETW(req.wValue, ls);
     373           0 :         USETW(req.wIndex, sc->sc_ctl_iface_no);
     374           0 :         USETW(req.wLength, 0);
     375             : 
     376           0 :         return usbd_do_request(sc->sc_udev, &req, 0);
     377           0 : }
     378             : 
     379             : void
     380           0 : uonerng_task(void *arg)
     381             : {
     382           0 :         struct uonerng_softc *sc = (struct uonerng_softc *) arg;
     383             :         usbd_status error;
     384           0 :         u_int32_t len, int_count, i;
     385             : #ifdef ONERNG_MEASURE_RATE
     386             :         time_t elapsed;
     387             :         int rate;
     388             : #endif
     389             : 
     390           0 :         usbd_setup_xfer(sc->sc_xfer, sc->sc_inpipe, NULL, sc->sc_buf,
     391             :             ONERNG_BUFSIZ,
     392             :             USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS | USBD_NO_COPY,
     393             :             ONERNG_TIMEOUT, NULL);
     394           0 :         error = usbd_transfer(sc->sc_xfer);
     395           0 :         if (error) {
     396           0 :                 printf("%s: xfer failed: %s\n", DEVNAME(sc),
     397           0 :                     usbd_errstr(error));
     398           0 :                 goto bail;
     399             :         }
     400           0 :         usbd_get_xfer_status(sc->sc_xfer, NULL, NULL, &len, NULL);
     401           0 :         if (len < sizeof(int)) {
     402           0 :                 printf("%s: xfer too short (%u bytes) - dropping\n",
     403           0 :                     DEVNAME(sc), len);
     404           0 :                 goto bail;
     405             :         }
     406             : 
     407             : #ifdef ONERNG_MEASURE_RATE
     408             :         if (sc->sc_first_run) {
     409             :                 sc->sc_counted_bytes = 0;
     410             :                 getmicrotime(&(sc->sc_start));
     411             :         }
     412             :         sc->sc_counted_bytes += len;
     413             :         getmicrotime(&(sc->sc_cur));
     414             :         elapsed = sc->sc_cur.tv_sec - sc->sc_start.tv_sec;
     415             :         if (elapsed >= ONERNG_RATE_SECONDS) {
     416             :                 rate = (8 * sc->sc_counted_bytes) / (elapsed * 1024);
     417             :                 printf("%s: transfer rate = %d kb/s\n", DEVNAME(sc), rate);
     418             : 
     419             :                 /* set up for next measurement */
     420             :                 sc->sc_counted_bytes = 0;
     421             :                 getmicrotime(&(sc->sc_start));
     422             :         }
     423             : #endif
     424             : 
     425           0 :         int_count = len / sizeof(int);
     426           0 :         for (i = 0; i < int_count; i++) {
     427           0 :                 enqueue_randomness(sc->sc_buf[i]);
     428             :         }
     429             : bail:
     430             : 
     431           0 :         if (sc->sc_first_run) {
     432           0 :                 sc->sc_first_run = 0;
     433           0 :         } else {
     434           0 :                 timeout_add_msec(&sc->sc_timeout, ONERNG_MSECS);
     435             :         }
     436           0 : }
     437             : 
     438             : void
     439           0 : uonerng_timeout(void *arg)
     440             : {
     441           0 :         struct uonerng_softc *sc = arg;
     442             : 
     443           0 :         usb_add_task(sc->sc_udev, &sc->sc_task);
     444           0 : }

Generated by: LCOV version 1.13