randomdev.c revision 164033
11573Srgrimes/*- 21573Srgrimes * Copyright (c) 2000-2004 Mark R V Murray 31573Srgrimes * All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer 101573Srgrimes * in this position and unchanged. 111573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121573Srgrimes * notice, this list of conditions and the following disclaimer in the 131573Srgrimes * documentation and/or other materials provided with the distribution. 141573Srgrimes * 151573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 161573Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 171573Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 181573Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 191573Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 201573Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 211573Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 221573Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 231573Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 241573Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 251573Srgrimes * 261573Srgrimes */ 271573Srgrimes 281573Srgrimes#include <sys/cdefs.h> 2950476Speter__FBSDID("$FreeBSD: head/sys/dev/random/randomdev.c 164033 2006-11-06 13:42:10Z rwatson $"); 301573Srgrimes 31302401Sjilles#include <sys/param.h> 321573Srgrimes#include <sys/systm.h> 3379531Sru#include <sys/bus.h> 341573Srgrimes#include <sys/conf.h> 351573Srgrimes#include <sys/fcntl.h> 361573Srgrimes#include <sys/filio.h> 3759460Sphantom#include <sys/kernel.h> 3859460Sphantom#include <sys/kthread.h> 391573Srgrimes#include <sys/lock.h> 4084306Sru#include <sys/malloc.h> 411573Srgrimes#include <sys/module.h> 4238930Sjkoshy#include <sys/mutex.h> 431573Srgrimes#include <sys/poll.h> 44100144Skeramida#include <sys/priv.h> 45100144Skeramida#include <sys/proc.h> 46108028Sru#include <sys/selinfo.h> 471573Srgrimes#include <sys/uio.h> 481573Srgrimes#include <sys/unistd.h> 491573Srgrimes 501573Srgrimes#include <machine/bus.h> 51131504Sru#include <machine/cpu.h> 52131504Sru 5338930Sjkoshy#include <dev/random/randomdev.h> 54108028Sru 5538930Sjkoshy#define RANDOM_MINOR 0 5638930Sjkoshy 57238835Skibstatic d_close_t random_close; 581573Srgrimesstatic d_read_t random_read; 591573Srgrimesstatic d_write_t random_write; 601573Srgrimesstatic d_ioctl_t random_ioctl; 611573Srgrimesstatic d_poll_t random_poll; 621573Srgrimes 631573Srgrimesstatic struct cdevsw random_cdevsw = { 641573Srgrimes .d_version = D_VERSION, 651573Srgrimes .d_close = random_close, 661573Srgrimes .d_read = random_read, 671573Srgrimes .d_write = random_write, 681573Srgrimes .d_ioctl = random_ioctl, 691573Srgrimes .d_poll = random_poll, 701573Srgrimes .d_name = "random", 711573Srgrimes}; 721573Srgrimes 731573Srgrimesstruct random_systat random_systat; 741573Srgrimes 751573Srgrimes/* For use with make_dev(9)/destroy_dev(9). */ 76238615Skibstatic struct cdev *random_dev; 77238615Skib 78238615Skib/* Used to fake out unused random calls in random_systat */ 79238615Skibvoid 8015082Smpprandom_null_func(void) 811573Srgrimes{ 821573Srgrimes} 83238615Skib 84238615Skib/* ARGSUSED */ 85238615Skibstatic int 86238615Skibrandom_close(struct cdev *dev __unused, int flags, int fmt __unused, 87238615Skib struct thread *td) 88238615Skib{ 89238615Skib if ((flags & FWRITE) && (priv_check(td, PRIV_RANDOM_RESEED) == 0) 90238615Skib && (securelevel_gt(td->td_ucred, 0) == 0)) { 91238615Skib (*random_systat.reseed)(); 92176957Santoine random_systat.seeded = 1; 93176957Santoine } 94176957Santoine 95176957Santoine return (0); 96176957Santoine} 97242429Sjilles 98238835Skib/* ARGSUSED */ 99238835Skibstatic int 100238835Skibrandom_read(struct cdev *dev __unused, struct uio *uio, int flag) 101238835Skib{ 102238835Skib int c, error = 0; 103176957Santoine void *random_buf; 104176957Santoine 105176957Santoine /* Blocking logic */ 106238835Skib if (!random_systat.seeded) 107242429Sjilles error = (*random_systat.block)(flag); 108238835Skib 109238835Skib /* The actual read */ 110176957Santoine if (!error) { 111176957Santoine 112238835Skib random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 113238835Skib 1141573Srgrimes while (uio->uio_resid > 0 && !error) { 1151573Srgrimes c = MIN(uio->uio_resid, PAGE_SIZE); 11694586Sasmodai c = (*random_systat.read)(random_buf, c); 11794586Sasmodai error = uiomove(random_buf, c, uio); 11894586Sasmodai } 11994586Sasmodai 12094586Sasmodai free(random_buf, M_TEMP); 12194586Sasmodai 1221573Srgrimes } 1231573Srgrimes 1241573Srgrimes return (error); 1251573Srgrimes} 1261573Srgrimes 1271573Srgrimes/* ARGSUSED */ 1281573Srgrimesstatic int 1291573Srgrimesrandom_write(struct cdev *dev __unused, struct uio *uio, int flag __unused) 1301573Srgrimes{ 13194586Sasmodai int c, error = 0; 13294586Sasmodai void *random_buf; 13394586Sasmodai 1341573Srgrimes random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 13594586Sasmodai 13694586Sasmodai while (uio->uio_resid > 0) { 13794586Sasmodai c = MIN((int)uio->uio_resid, PAGE_SIZE); 1381573Srgrimes error = uiomove(random_buf, c, uio); 1391573Srgrimes if (error) 1401573Srgrimes break; 1411573Srgrimes (*random_systat.write)(random_buf, c); 1421573Srgrimes } 1431573Srgrimes 1441573Srgrimes free(random_buf, M_TEMP); 1451573Srgrimes 1461573Srgrimes return (error); 1471573Srgrimes} 1481573Srgrimes 1491573Srgrimes/* ARGSUSED */ 1501573Srgrimesstatic int 1511573Srgrimesrandom_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, 1521573Srgrimes int flags __unused, struct thread *td __unused) 1531573Srgrimes{ 1541573Srgrimes int error = 0; 1551573Srgrimes 1561573Srgrimes switch (cmd) { 1571573Srgrimes /* Really handled in upper layer */ 1581573Srgrimes case FIOASYNC: 1591573Srgrimes case FIONBIO: 1601573Srgrimes break; 1611573Srgrimes default: 1621573Srgrimes error = ENOTTY; 1631573Srgrimes } 16479754Sdd return (error); 1651573Srgrimes} 1661573Srgrimes 167230648Stijl/* ARGSUSED */ 168230648Stijlstatic int 169230648Stijlrandom_poll(struct cdev *dev __unused, int events, struct thread *td) 170230648Stijl{ 171230648Stijl int revents = 0; 172230648Stijl 173230648Stijl if (events & (POLLIN | POLLRDNORM)) { 174246763Sian if (random_systat.seeded) 175230648Stijl revents = events & (POLLIN | POLLRDNORM); 176230648Stijl else 177230648Stijl revents = (*random_systat.poll) (events,td); 178230648Stijl } 179230648Stijl return (revents); 180230648Stijl} 181230648Stijl 182230648Stijl/* ARGSUSED */ 1831573Srgrimesstatic int 1841573Srgrimesrandom_modevent(module_t mod __unused, int type, void *data __unused) 1851573Srgrimes{ 1861573Srgrimes int error = 0; 1871573Srgrimes 1881573Srgrimes switch (type) { 1891573Srgrimes case MOD_LOAD: 1901573Srgrimes random_ident_hardware(&random_systat); 1911573Srgrimes (*random_systat.init)(); 1921573Srgrimes 19314855Smpp if (bootverbose) 194108028Sru printf("random: <entropy source, %s>\n", 19514855Smpp random_systat.ident); 1961573Srgrimes 1971573Srgrimes random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, 1981573Srgrimes UID_ROOT, GID_WHEEL, 0666, "random"); 1991573Srgrimes make_dev_alias(random_dev, "urandom"); /* XXX Deprecated */ 2001573Srgrimes 2011573Srgrimes break; 2021573Srgrimes 2031573Srgrimes case MOD_UNLOAD: 2041573Srgrimes (*random_systat.deinit)(); 20577115Sdillon 206131504Sru destroy_dev(random_dev); 207131504Sru 208131504Sru break; 209131504Sru 21077115Sdillon case MOD_SHUTDOWN: 21177115Sdillon break; 2121573Srgrimes 2131573Srgrimes default: 2141573Srgrimes error = EOPNOTSUPP; 2151573Srgrimes break; 2161573Srgrimes 2171573Srgrimes } 2181573Srgrimes return (error); 2191573Srgrimes} 2201573Srgrimes 2211573SrgrimesDEV_MODULE(random, random_modevent, NULL); 2221573SrgrimesMODULE_VERSION(random, 1); 2231573Srgrimes