/* * notrandom - /dev/notrandom device driver, provides not random numbers. * Written for Solaris 10 x86/SPARC. * * This produces a series of reliable not random numbers (the number 7). * It is a faster device than /dev/random. * * 27-Nov-2005, ver 0.70 (first release!) * * INSTALL: * gcc/x86, * gcc -D_KERNEL -c notrandom.c * gcc/sparc, * gcc -D_KERNEL -m64 -c notrandom.c * both, * ld -r -o notrandom notrandom.o * cp notrandom /kernel/drv * echo 'name="notrandom" parent="pseudo";' > /kernel/drv/notrandom.conf * add_drv -m '* 0666 root sys' notrandom * modload -p drv/notrandom * ln -s '../devices/pseudo/notrandom@0:c,raw' /dev/notrandom * * BASED ON: * Sample Solaris 8 Drivers (SUNWdrvs8), with Solaris 10 DDI * updates applied. * * WARNING: * This is fairly untested so far. As small mistakes in driver code can * cause the kernel to panic, this should only be run on test servers. * * PORTIONS: Copyright (c) 2005 Brendan Gregg. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * (http://www.gnu.org/copyleft/gpl.html) * * 27-Nov-2005 Brendan Gregg Created this. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Device Settings */ #define NR_NUMBER 7 #define NR_MAXPHYS (1024*1024) #define NR_MAXIOVEC 1024 /* * Character Driver Roadmap * * modlinkage devstate * | * modldrv * | * dev_ops * | * cb_ops * * Chapter 14, http://docs.sun.com/app/docs/doc/816-4854 */ /* * Device State */ typedef struct { dev_info_t *dip; /* devinfo */ } nr_devstate_t; static void *nr_state; /* nr_devstate_t */ /* * Device Char/Block Operations - cb_ops(9S) */ static int nr_open(dev_t *devp, int flag, int otyp, cred_t *cred); static int nr_strategy(struct buf *bp); static int nr_read(dev_t dev, struct uio *uiop, cred_t *credp); static int nr_write(dev_t dev, struct uio *uiop, cred_t *credp); static int nr_print(dev_t dev, char *str); static struct cb_ops nr_cb_ops = { nr_open, /* cb_open */ nulldev, /* cb_close */ nodev, /* cb_strategy */ nodev, /* cb_print */ nodev, /* cb_dump */ nr_read, /* cb_read */ nr_write, /* cb_write */ nodev, /* cb_ioctl */ nodev, /* cb_devmap */ nodev, /* cb_mmap */ nodev, /* cb_segmap */ nochpoll, /* cb_chpoll */ ddi_prop_op, /* cb_prop_op */ (struct streamtab *)NULL, /* cb_stream */ D_NEW | D_MP, /* cb_flag */ 0, /* cb_rev */ nodev, /* cb_aread */ nodev /* cb_awrite */ }; /* * Device Operations - dev_ops(9S) */ static int nr_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result); static int nr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); static int nr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); static struct dev_ops nr_ops = { DEVO_REV, /* devo_rev */ 0, /* devo_refcnt */ nr_getinfo, /* devo_getinfo */ nulldev, /* devo_identify */ nulldev, /* devo_probe */ nr_attach, /* devo_attach */ nr_detach, /* devo_detach */ nodev, /* devo_reset */ &nr_cb_ops, /* devo_cb_ops */ (struct bus_ops *)NULL, /* devo_bus_ops */ nulldev /* devo_power */ }; /* * Module Linkage - modldrv(9S) */ extern struct mod_ops mod_driverops; static struct modldrv modldrv = { &mod_driverops, /* module ops */ "notrandom driver v0.70", /* link info */ &nr_ops /* device ops */ }; static struct modlinkage modlinkage = { MODREV_1, &modldrv, 0 }; int _init(void) { int status; if ((status = ddi_soft_state_init(&nr_state, sizeof (nr_devstate_t), 1)) != 0) { return (status); } if ((status = mod_install(&modlinkage)) != 0) { ddi_soft_state_fini(&nr_state); } return (status); } int _fini(void) { int status; if ((status = mod_remove(&modlinkage)) != 0) { return (status); } ddi_soft_state_fini(&nr_state); return (status); } int _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); } static int nr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { int instance; nr_devstate_t *nsp; switch (cmd) { case DDI_ATTACH: instance = ddi_get_instance(dip); if (ddi_soft_state_zalloc(nr_state, instance) != DDI_SUCCESS) { cmn_err(CE_CONT, "%s%d: can't allocate state\n", ddi_get_name(dip), instance); return (DDI_FAILURE); } else nsp = ddi_get_soft_state(nr_state, instance); if (ddi_create_minor_node(dip, "c,raw", S_IFCHR, instance, DDI_PSEUDO, 0) == DDI_FAILURE) { ddi_remove_minor_node(dip, NULL); goto attach_failed; } nsp->dip = dip; ddi_report_dev(dip); cmn_err(CE_CONT, "%s%d: notrandom loaded.\n", ddi_get_name(dip), ddi_get_instance(dip)); return (DDI_SUCCESS); default: return (DDI_FAILURE); } attach_failed: cmn_err(CE_WARN, "%s%d: notrandom failed.\n", ddi_get_name(dip), ddi_get_instance(dip)); /* cleanup */ (void) nr_detach(dip, DDI_DETACH); return (DDI_FAILURE); } static int nr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { int instance; register nr_devstate_t *nsp; switch (cmd) { case DDI_DETACH: ddi_prop_remove_all(dip); instance = ddi_get_instance(dip); nsp = ddi_get_soft_state(nr_state, instance); ddi_remove_minor_node(dip, NULL); ddi_soft_state_free(nr_state, instance); return (DDI_SUCCESS); default: return (DDI_FAILURE); } } /*ARGSUSED*/ static int nr_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) { nr_devstate_t *nsp; int error = DDI_FAILURE; switch (infocmd) { case DDI_INFO_DEVT2DEVINFO: if ((nsp = ddi_get_soft_state(nr_state, getminor((dev_t)arg))) != NULL) { *result = nsp->dip; error = DDI_SUCCESS; } else *result = NULL; break; case DDI_INFO_DEVT2INSTANCE: *result = (void *)getminor((dev_t)arg); error = DDI_SUCCESS; break; default: break; } return (error); } /*ARGSUSED*/ static int nr_open(dev_t *devp, int flag, int otyp, cred_t *cred) { if (otyp != OTYP_CHR) return (EINVAL); if (ddi_get_soft_state(nr_state, getminor(*devp)) == NULL) return (ENXIO); return (0); } /*ARGSUSED*/ static int nr_read(dev_t dev, struct uio *uiop, cred_t *credp) { int i; int error; /* error on reads that are too large */ if ((uiop->uio_iov->iov_len > NR_MAXPHYS) || (uiop->uio_iovcnt > NR_MAXIOVEC)) { return (EIO); } /* return notrandom number */ while (uiop->uio_iovcnt > 0) { i = 0; /* * this is an awfully slow way to send bytes, I'll fix it * in later versions. (it's still faster than /dev/random!) */ while ((uiop->uio_resid > 0) && (++i < NR_MAXPHYS)) error = ureadc((int)NR_NUMBER, uiop); uiop->uio_iov++; uiop->uio_iovcnt--; } return (error); } /*ARGSUSED*/ static int nr_write(dev_t dev, register struct uio *uiop, cred_t *credp) { int instance = getminor(dev); nr_devstate_t *nsp = ddi_get_soft_state(nr_state, instance); return (0); }