162053Smarkm/*- 2256381Smarkm * Copyright (c) 2000-2013 Mark R V Murray 3254147Sobrien * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> 462053Smarkm * All rights reserved. 562053Smarkm * 662053Smarkm * Redistribution and use in source and binary forms, with or without 762053Smarkm * modification, are permitted provided that the following conditions 862053Smarkm * are met: 962053Smarkm * 1. Redistributions of source code must retain the above copyright 1062053Smarkm * notice, this list of conditions and the following disclaimer 1162053Smarkm * in this position and unchanged. 1262053Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1362053Smarkm * notice, this list of conditions and the following disclaimer in the 1462053Smarkm * documentation and/or other materials provided with the distribution. 1562053Smarkm * 1662053Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1762053Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1862053Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1962053Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2062053Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2162053Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2262053Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2362053Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2462053Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2562053Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2662053Smarkm * 2762053Smarkm */ 2862053Smarkm 29119418Sobrien#include <sys/cdefs.h> 30119418Sobrien__FBSDID("$FreeBSD$"); 31119418Sobrien 3262053Smarkm#include <sys/param.h> 3362053Smarkm#include <sys/systm.h> 3476166Smarkm#include <sys/bus.h> 3562053Smarkm#include <sys/conf.h> 3676166Smarkm#include <sys/fcntl.h> 3774771Smarkm#include <sys/filio.h> 3862053Smarkm#include <sys/kernel.h> 3974072Smarkm#include <sys/kthread.h> 4076166Smarkm#include <sys/lock.h> 4162053Smarkm#include <sys/malloc.h> 42129876Sphk#include <sys/module.h> 4376166Smarkm#include <sys/mutex.h> 4467112Smarkm#include <sys/poll.h> 45164033Srwatson#include <sys/priv.h> 4683366Sjulian#include <sys/proc.h> 47256381Smarkm#include <sys/random.h> 4870834Swollman#include <sys/selinfo.h> 4976166Smarkm#include <sys/uio.h> 5076166Smarkm#include <sys/unistd.h> 5174072Smarkm 5262053Smarkm#include <machine/bus.h> 5374072Smarkm#include <machine/cpu.h> 5462053Smarkm 55256381Smarkm#include <dev/random/randomdev.h> 56256381Smarkm#include <dev/random/randomdev_soft.h> 57255362Smarkm#include <dev/random/random_adaptors.h> 58256381Smarkm#include <dev/random/random_harvestq.h> 59256381Smarkm#include <dev/random/live_entropy_sources.h> 6062053Smarkm 61122871Smarkm#define RANDOM_MINOR 0 6262053Smarkm 63128059Smarkmstatic d_read_t random_read; 64128059Smarkmstatic d_write_t random_write; 65128059Smarkmstatic d_ioctl_t random_ioctl; 66128059Smarkmstatic d_poll_t random_poll; 67122871Smarkm 6862053Smarkmstatic struct cdevsw random_cdevsw = { 69128059Smarkm .d_version = D_VERSION, 70128059Smarkm .d_read = random_read, 71128059Smarkm .d_write = random_write, 72128059Smarkm .d_ioctl = random_ioctl, 73128059Smarkm .d_poll = random_poll, 74128059Smarkm .d_name = "random", 7562053Smarkm}; 7662053Smarkm 7762053Smarkm/* For use with make_dev(9)/destroy_dev(9). */ 78130585Sphkstatic struct cdev *random_dev; 7962053Smarkm 8091600Smarkm/* ARGSUSED */ 8162053Smarkmstatic int 82130585Sphkrandom_read(struct cdev *dev __unused, struct uio *uio, int flag) 8362053Smarkm{ 84128059Smarkm int c, error = 0; 85128367Smarkm void *random_buf; 8662053Smarkm 87128059Smarkm /* Blocking logic */ 88254147Sobrien if (!random_adaptor->seeded) 89254147Sobrien error = (*random_adaptor->block)(flag); 90128059Smarkm 91128059Smarkm /* The actual read */ 92128059Smarkm if (!error) { 93128367Smarkm 94256381Smarkm random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); 95128367Smarkm 96128059Smarkm while (uio->uio_resid > 0 && !error) { 97128059Smarkm c = MIN(uio->uio_resid, PAGE_SIZE); 98254147Sobrien c = (*random_adaptor->read)(random_buf, c); 99128059Smarkm error = uiomove(random_buf, c, uio); 100128059Smarkm } 101256381Smarkm /* Finished reading; let the source know so it can do some 102256381Smarkm * optional housekeeping */ 103256381Smarkm (*random_adaptor->read)(NULL, 0); 104128367Smarkm 105256381Smarkm free(random_buf, M_ENTROPY); 106128367Smarkm 10767286Speter } 108128151Smarkm 109128059Smarkm return (error); 11062053Smarkm} 11162053Smarkm 11291600Smarkm/* ARGSUSED */ 11362053Smarkmstatic int 114130585Sphkrandom_write(struct cdev *dev __unused, struct uio *uio, int flag __unused) 11562053Smarkm{ 11662053Smarkm 117256381Smarkm /* We used to allow this to insert userland entropy. 118256381Smarkm * We don't any more because (1) this so-called entropy 119256381Smarkm * is usually lousy and (b) its vaguely possible to 120256381Smarkm * mess with entropy harvesting by overdoing a write. 121256381Smarkm * Now we just ignore input like /dev/null does. 122256381Smarkm */ 123256381Smarkm uio->uio_resid = 0; 124128367Smarkm 125256381Smarkm return (0); 12662053Smarkm} 12762053Smarkm 12891600Smarkm/* ARGSUSED */ 12962053Smarkmstatic int 130130585Sphkrandom_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, 13191600Smarkm int flags __unused, struct thread *td __unused) 13265686Smarkm{ 133128059Smarkm int error = 0; 134128059Smarkm 13574771Smarkm switch (cmd) { 136128059Smarkm /* Really handled in upper layer */ 13774771Smarkm case FIOASYNC: 13874771Smarkm case FIONBIO: 139128059Smarkm break; 14074771Smarkm default: 141128059Smarkm error = ENOTTY; 14274771Smarkm } 143128059Smarkm return (error); 14465686Smarkm} 14565686Smarkm 14691600Smarkm/* ARGSUSED */ 14765686Smarkmstatic int 148130585Sphkrandom_poll(struct cdev *dev __unused, int events, struct thread *td) 14967112Smarkm{ 150128059Smarkm int revents = 0; 15167112Smarkm 15267112Smarkm if (events & (POLLIN | POLLRDNORM)) { 153254147Sobrien if (random_adaptor->seeded) 15467112Smarkm revents = events & (POLLIN | POLLRDNORM); 15567112Smarkm else 156256381Smarkm revents = (*random_adaptor->poll)(events, td); 15767112Smarkm } 158128059Smarkm return (revents); 15967112Smarkm} 16067112Smarkm 161254147Sobrienstatic void 162254147Sobrienrandom_initialize(void *p, struct random_adaptor *s) 163254147Sobrien{ 164256381Smarkm static int random_inited = 0; 165256381Smarkm 166254147Sobrien if (random_inited) { 167254147Sobrien printf("random: <%s> already initialized\n", 168254147Sobrien random_adaptor->ident); 169254147Sobrien return; 170254147Sobrien } 171254147Sobrien 172254147Sobrien random_adaptor = s; 173254147Sobrien 174254147Sobrien (s->init)(); 175254147Sobrien 176254147Sobrien printf("random: <%s> initialized\n", s->ident); 177254147Sobrien 178256381Smarkm /* Use an appropriately evil mode for those who are concerned 179256381Smarkm * with daemons */ 180254147Sobrien random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, 181254147Sobrien RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random"); 182256381Smarkm make_dev_alias(random_dev, "urandom"); /* compatibility */ 183254147Sobrien 184254147Sobrien /* mark random(4) as initialized, to avoid being called again */ 185254147Sobrien random_inited = 1; 186254147Sobrien} 187254147Sobrien 18891600Smarkm/* ARGSUSED */ 18967112Smarkmstatic int 19091600Smarkmrandom_modevent(module_t mod __unused, int type, void *data __unused) 19162053Smarkm{ 192256381Smarkm static eventhandler_tag attach_tag = NULL; 193128059Smarkm int error = 0; 19465686Smarkm 195128059Smarkm switch (type) { 19662053Smarkm case MOD_LOAD: 197255362Smarkm random_adaptor_choose(&random_adaptor); 19871037Smarkm 199254147Sobrien if (random_adaptor == NULL) { 200256381Smarkm printf("random: No random adaptor attached, " 201256381Smarkm "postponing initialization\n"); 202254147Sobrien attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach, 203254147Sobrien random_initialize, NULL, EVENTHANDLER_PRI_ANY); 204256381Smarkm } else 205254147Sobrien random_initialize(NULL, random_adaptor); 20671037Smarkm 207128059Smarkm break; 20874072Smarkm 20962053Smarkm case MOD_UNLOAD: 210254147Sobrien if (random_adaptor != NULL) { 211254147Sobrien (*random_adaptor->deinit)(); 212254147Sobrien destroy_dev(random_dev); 213254147Sobrien } 214254147Sobrien /* Unregister the event handler */ 215256381Smarkm if (attach_tag != NULL) 216254147Sobrien EVENTHANDLER_DEREGISTER(random_adaptor_attach, 217254147Sobrien attach_tag); 21874072Smarkm 219128059Smarkm break; 220122871Smarkm 22162053Smarkm case MOD_SHUTDOWN: 222128059Smarkm break; 22362053Smarkm 224132199Sphk default: 225132199Sphk error = EOPNOTSUPP; 226132199Sphk break; 227132199Sphk 22862053Smarkm } 229128059Smarkm return (error); 23062053Smarkm} 23162053Smarkm 23262053SmarkmDEV_MODULE(random, random_modevent, NULL); 233133036SmarkmMODULE_VERSION(random, 1); 234