randomdev.c revision 253779
1/*- 2 * Copyright (c) 2000-2004 Mark R V Murray 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: head/sys/dev/random/randomdev.c 253779 2013-07-29 20:26:27Z obrien $"); 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/bus.h> 34#include <sys/conf.h> 35#include <sys/fcntl.h> 36#include <sys/filio.h> 37#include <sys/kernel.h> 38#include <sys/kthread.h> 39#include <sys/lock.h> 40#include <sys/malloc.h> 41#include <sys/module.h> 42#include <sys/mutex.h> 43#include <sys/poll.h> 44#include <sys/priv.h> 45#include <sys/proc.h> 46#include <sys/selinfo.h> 47#include <sys/uio.h> 48#include <sys/unistd.h> 49 50#include <machine/bus.h> 51#include <machine/cpu.h> 52 53#include <dev/random/randomdev.h> 54 55#define RANDOM_MINOR 0 56 57static d_close_t random_close; 58static d_read_t random_read; 59static d_write_t random_write; 60static d_ioctl_t random_ioctl; 61static d_poll_t random_poll; 62 63static struct cdevsw random_cdevsw = { 64 .d_version = D_VERSION, 65 .d_close = random_close, 66 .d_read = random_read, 67 .d_write = random_write, 68 .d_ioctl = random_ioctl, 69 .d_poll = random_poll, 70 .d_name = "random", 71}; 72 73static struct random_adaptor *random_adaptor; 74static eventhandler_tag attach_tag; 75static int random_inited; 76 77 78/* For use with make_dev(9)/destroy_dev(9). */ 79static struct cdev *random_dev; 80 81/* Used to fake out unused random calls in random_adaptor */ 82void 83random_null_func(void) 84{ 85} 86 87/* ARGSUSED */ 88static int 89random_close(struct cdev *dev __unused, int flags, int fmt __unused, 90 struct thread *td) 91{ 92 if ((flags & FWRITE) && (priv_check(td, PRIV_RANDOM_RESEED) == 0) 93 && (securelevel_gt(td->td_ucred, 0) == 0)) { 94 (*random_adaptor->reseed)(); 95 random_adaptor->seeded = 1; 96 arc4rand(NULL, 0, 1); /* Reseed arc4random as well. */ 97 } 98 99 return (0); 100} 101 102/* ARGSUSED */ 103static int 104random_read(struct cdev *dev __unused, struct uio *uio, int flag) 105{ 106 int c, error = 0; 107 void *random_buf; 108 109 /* Blocking logic */ 110 if (!random_adaptor->seeded) 111 error = (*random_adaptor->block)(flag); 112 113 /* The actual read */ 114 if (!error) { 115 116 random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 117 118 while (uio->uio_resid > 0 && !error) { 119 c = MIN(uio->uio_resid, PAGE_SIZE); 120 c = (*random_adaptor->read)(random_buf, c); 121 error = uiomove(random_buf, c, uio); 122 } 123 124 free(random_buf, M_TEMP); 125 126 } 127 128 return (error); 129} 130 131/* ARGSUSED */ 132static int 133random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused) 134{ 135 int c, error = 0; 136 void *random_buf; 137 138 random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 139 140 while (uio->uio_resid > 0) { 141 c = MIN((int)uio->uio_resid, PAGE_SIZE); 142 error = uiomove(random_buf, c, uio); 143 if (error) 144 break; 145 (*random_adaptor->write)(random_buf, c); 146 } 147 148 free(random_buf, M_TEMP); 149 150 return (error); 151} 152 153/* ARGSUSED */ 154static int 155random_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, 156 int flags __unused, struct thread *td __unused) 157{ 158 int error = 0; 159 160 switch (cmd) { 161 /* Really handled in upper layer */ 162 case FIOASYNC: 163 case FIONBIO: 164 break; 165 default: 166 error = ENOTTY; 167 } 168 return (error); 169} 170 171/* ARGSUSED */ 172static int 173random_poll(struct cdev *dev __unused, int events, struct thread *td) 174{ 175 int revents = 0; 176 177 if (events & (POLLIN | POLLRDNORM)) { 178 if (random_adaptor->seeded) 179 revents = events & (POLLIN | POLLRDNORM); 180 else 181 revents = (*random_adaptor->poll) (events,td); 182 } 183 return (revents); 184} 185 186static void 187random_initialize(void *p, struct random_adaptor *s) 188{ 189 if (random_inited) { 190 printf("random: <%s> already initialized\n", 191 random_adaptor->ident); 192 return; 193 } 194 195 random_adaptor = s; 196 197 (s->init)(); 198 199 printf("random: <%s> initialized\n", s->ident); 200 201 random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, 202 RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random"); 203 make_dev_alias(random_dev, "urandom"); /* XXX Deprecated */ 204 205 /* mark random(4) as initialized, to avoid being called again */ 206 random_inited = 1; 207} 208 209/* ARGSUSED */ 210static int 211random_modevent(module_t mod __unused, int type, void *data __unused) 212{ 213 int error = 0; 214 215 switch (type) { 216 case MOD_LOAD: 217 random_ident_hardware(&random_adaptor); 218 219 if (random_adaptor == NULL) { 220 printf( 221 "random: No random adaptor attached, postponing initialization\n"); 222 attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach, 223 random_initialize, NULL, EVENTHANDLER_PRI_ANY); 224 } else { 225 random_initialize(NULL, random_adaptor); 226 } 227 228 break; 229 230 case MOD_UNLOAD: 231 if (random_adaptor != NULL) { 232 (*random_adaptor->deinit)(); 233 destroy_dev(random_dev); 234 } 235 /* Unregister the event handler */ 236 if (attach_tag != NULL) { 237 EVENTHANDLER_DEREGISTER(random_adaptor_attach, 238 attach_tag); 239 } 240 241 break; 242 243 case MOD_SHUTDOWN: 244 break; 245 246 default: 247 error = EOPNOTSUPP; 248 break; 249 250 } 251 return (error); 252} 253 254DEV_MODULE(random, random_modevent, NULL); 255MODULE_VERSION(random, 1); 256