randomdev.c revision 253845
156893Sfenner/*- 256893Sfenner * Copyright (c) 2000-2004 Mark R V Murray 356893Sfenner * All rights reserved. 456893Sfenner * 556893Sfenner * Redistribution and use in source and binary forms, with or without 656893Sfenner * modification, are permitted provided that the following conditions 756893Sfenner * are met: 856893Sfenner * 1. Redistributions of source code must retain the above copyright 956893Sfenner * notice, this list of conditions and the following disclaimer 1056893Sfenner * in this position and unchanged. 1156893Sfenner * 2. Redistributions in binary form must reproduce the above copyright 1256893Sfenner * notice, this list of conditions and the following disclaimer in the 1356893Sfenner * documentation and/or other materials provided with the distribution. 1456893Sfenner * 1556893Sfenner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1656893Sfenner * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1756893Sfenner * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1856893Sfenner * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1956893Sfenner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2056893Sfenner * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2156893Sfenner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2256893Sfenner * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2356893Sfenner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2475115Sfenner * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2556893Sfenner * 2656893Sfenner */ 2756893Sfenner 2856893Sfenner#include <sys/cdefs.h> 2956893Sfenner__FBSDID("$FreeBSD: head/sys/dev/random/randomdev.c 253845 2013-07-31 17:21:18Z obrien $"); 3056893Sfenner 3156893Sfenner#include <sys/param.h> 3256893Sfenner#include <sys/systm.h> 3356893Sfenner#include <sys/bus.h> 3456893Sfenner#include <sys/conf.h> 3556893Sfenner#include <sys/fcntl.h> 3656893Sfenner#include <sys/filio.h> 3756893Sfenner#include <sys/kernel.h> 3856893Sfenner#include <sys/kthread.h> 3956893Sfenner#include <sys/lock.h> 4056893Sfenner#include <sys/malloc.h> 4156893Sfenner#include <sys/module.h> 4256893Sfenner#include <sys/mutex.h> 4356893Sfenner#include <sys/poll.h> 4456893Sfenner#include <sys/priv.h> 4556893Sfenner#include <sys/proc.h> 4675115Sfenner#include <sys/selinfo.h> 4756893Sfenner#include <sys/uio.h> 4875115Sfenner#include <sys/unistd.h> 4975115Sfenner 5056893Sfenner#include <machine/bus.h> 5156893Sfenner#include <machine/cpu.h> 5256893Sfenner 5356893Sfenner#include <dev/random/randomdev.h> 5475115Sfenner 5575115Sfenner#define RANDOM_MINOR 0 5675115Sfenner 5756893Sfennerstatic d_close_t random_close; 5856893Sfennerstatic d_read_t random_read; 5975115Sfennerstatic d_write_t random_write; 6075115Sfennerstatic d_ioctl_t random_ioctl; 6175115Sfennerstatic d_poll_t random_poll; 6275115Sfenner 6356893Sfennerstatic struct cdevsw random_cdevsw = { 6475115Sfenner .d_version = D_VERSION, 6575115Sfenner .d_close = random_close, 6675115Sfenner .d_read = random_read, 6775115Sfenner .d_write = random_write, 6856893Sfenner .d_ioctl = random_ioctl, 6956893Sfenner .d_poll = random_poll, 7056893Sfenner .d_name = "random", 7175115Sfenner}; 7256893Sfenner 7356893Sfennerstruct random_systat *random_systat; 7456893Sfenner 7556893Sfenner/* For use with make_dev(9)/destroy_dev(9). */ 7675115Sfennerstatic struct cdev *random_dev; 7756893Sfenner 7856893Sfenner/* Used to fake out unused random calls in random_systat */ 7975115Sfennervoid 8056893Sfennerrandom_null_func(void) 8156893Sfenner{ 8256893Sfenner} 8356893Sfenner 8456893Sfenner/* ARGSUSED */ 8556893Sfennerstatic int 8656893Sfennerrandom_close(struct cdev *dev __unused, int flags, int fmt __unused, 8756893Sfenner struct thread *td) 8856893Sfenner{ 8975115Sfenner if ((flags & FWRITE) && (priv_check(td, PRIV_RANDOM_RESEED) == 0) 9056893Sfenner && (securelevel_gt(td->td_ucred, 0) == 0)) { 9156893Sfenner (*random_systat->reseed)(); 9256893Sfenner random_systat->seeded = 1; 9356893Sfenner arc4rand(NULL, 0, 1); /* Reseed arc4random as well. */ 9456893Sfenner } 9556893Sfenner 9656893Sfenner return (0); 9756893Sfenner} 9875115Sfenner 9956893Sfenner/* ARGSUSED */ 10056893Sfennerstatic int 10156893Sfennerrandom_read(struct cdev *dev __unused, struct uio *uio, int flag) 10256893Sfenner{ 10356893Sfenner int c, error = 0; 10475115Sfenner void *random_buf; 10556893Sfenner 10656893Sfenner /* Blocking logic */ 10756893Sfenner if (!random_systat->seeded) 10856893Sfenner error = (*random_systat->block)(flag); 10956893Sfenner 11056893Sfenner /* The actual read */ 11156893Sfenner if (!error) { 11256893Sfenner 11356893Sfenner random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 11456893Sfenner 11556893Sfenner while (uio->uio_resid > 0 && !error) { 11656893Sfenner c = MIN(uio->uio_resid, PAGE_SIZE); 11756893Sfenner c = (*random_systat->read)(random_buf, c); 11856893Sfenner error = uiomove(random_buf, c, uio); 11956893Sfenner } 12056893Sfenner 12156893Sfenner free(random_buf, M_TEMP); 12256893Sfenner 12356893Sfenner } 12456893Sfenner 12556893Sfenner return (error); 12675115Sfenner} 12775115Sfenner 12875115Sfenner/* ARGSUSED */ 12975115Sfennerstatic int 13056893Sfennerrandom_write(struct cdev *dev __unused, struct uio *uio, int flag __unused) 13175115Sfenner{ 13256893Sfenner int c, error = 0; 13356893Sfenner void *random_buf; 13456893Sfenner 13556893Sfenner random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 13656893Sfenner 13756893Sfenner while (uio->uio_resid > 0) { 13856893Sfenner c = MIN((int)uio->uio_resid, PAGE_SIZE); 13956893Sfenner error = uiomove(random_buf, c, uio); 14056893Sfenner if (error) 14156893Sfenner break; 14256893Sfenner (*random_systat->write)(random_buf, c); 14356893Sfenner } 14456893Sfenner 14556893Sfenner free(random_buf, M_TEMP); 14656893Sfenner 14756893Sfenner return (error); 14856893Sfenner} 14956893Sfenner 15056893Sfenner/* ARGSUSED */ 15156893Sfennerstatic int 15256893Sfennerrandom_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, 15356893Sfenner int flags __unused, struct thread *td __unused) 15456893Sfenner{ 15556893Sfenner int error = 0; 15656893Sfenner 15756893Sfenner switch (cmd) { 15856893Sfenner /* Really handled in upper layer */ 15956893Sfenner case FIOASYNC: 16056893Sfenner case FIONBIO: 16156893Sfenner break; 16256893Sfenner default: 16356893Sfenner error = ENOTTY; 16456893Sfenner } 16556893Sfenner return (error); 16656893Sfenner} 16756893Sfenner 16856893Sfenner/* ARGSUSED */ 16956893Sfennerstatic int 17056893Sfennerrandom_poll(struct cdev *dev __unused, int events, struct thread *td) 17156893Sfenner{ 17256893Sfenner int revents = 0; 17356893Sfenner 17456893Sfenner if (events & (POLLIN | POLLRDNORM)) { 17556893Sfenner if (random_systat->seeded) 17656893Sfenner revents = events & (POLLIN | POLLRDNORM); 17756893Sfenner else 17856893Sfenner revents = (*random_systat->poll) (events,td); 17956893Sfenner } 18056893Sfenner return (revents); 18156893Sfenner} 18256893Sfenner 18356893Sfenner/* ARGSUSED */ 18456893Sfennerstatic int 18556893Sfennerrandom_modevent(module_t mod __unused, int type, void *data __unused) 18656893Sfenner{ 18756893Sfenner int error = 0; 18856893Sfenner 18956893Sfenner switch (type) { 19056893Sfenner case MOD_LOAD: 19156893Sfenner random_ident_hardware(&random_systat); 19256893Sfenner (*random_systat->init)(); 19356893Sfenner 19456893Sfenner if (bootverbose) 19556893Sfenner printf("random: <entropy source, %s>\n", 19656893Sfenner random_systat->ident); 19756893Sfenner 19856893Sfenner random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, 19956893Sfenner RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random"); 20056893Sfenner make_dev_alias(random_dev, "urandom"); /* XXX Deprecated */ 20156893Sfenner 20256893Sfenner break; 20356893Sfenner 20456893Sfenner case MOD_UNLOAD: 20556893Sfenner (*random_systat->deinit)(); 20656893Sfenner 20756893Sfenner destroy_dev(random_dev); 20856893Sfenner 20956893Sfenner break; 21056893Sfenner 21156893Sfenner case MOD_SHUTDOWN: 21256893Sfenner break; 21356893Sfenner 21456893Sfenner default: 21556893Sfenner error = EOPNOTSUPP; 21656893Sfenner break; 21756893Sfenner 21856893Sfenner } 21975115Sfenner return (error); 22056893Sfenner} 22156893Sfenner 22256893SfennerDEV_MODULE(random, random_modevent, NULL); 22356893SfennerMODULE_VERSION(random, 1); 22456893Sfenner