10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53042Sedp * Common Development and Distribution License (the "License"). 63042Sedp * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 223042Sedp * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 290Sstevel@tonic-gate /* All Rights Reserved */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate 320Sstevel@tonic-gate /* 330Sstevel@tonic-gate * STREAMS Administrative Driver 340Sstevel@tonic-gate * 350Sstevel@tonic-gate * Currently only handles autopush and module name verification. 360Sstevel@tonic-gate */ 370Sstevel@tonic-gate 380Sstevel@tonic-gate #include <sys/types.h> 390Sstevel@tonic-gate #include <sys/param.h> 400Sstevel@tonic-gate #include <sys/errno.h> 410Sstevel@tonic-gate #include <sys/stream.h> 420Sstevel@tonic-gate #include <sys/stropts.h> 430Sstevel@tonic-gate #include <sys/strsubr.h> 440Sstevel@tonic-gate #include <sys/strsun.h> 450Sstevel@tonic-gate #include <sys/conf.h> 460Sstevel@tonic-gate #include <sys/sad.h> 470Sstevel@tonic-gate #include <sys/cred.h> 480Sstevel@tonic-gate #include <sys/debug.h> 490Sstevel@tonic-gate #include <sys/ddi.h> 500Sstevel@tonic-gate #include <sys/sunddi.h> 510Sstevel@tonic-gate #include <sys/stat.h> 520Sstevel@tonic-gate #include <sys/cmn_err.h> 530Sstevel@tonic-gate #include <sys/systm.h> 540Sstevel@tonic-gate #include <sys/modctl.h> 550Sstevel@tonic-gate #include <sys/priv_names.h> 563042Sedp #include <sys/sysmacros.h> 570Sstevel@tonic-gate 580Sstevel@tonic-gate static int sadopen(queue_t *, dev_t *, int, int, cred_t *); 590Sstevel@tonic-gate static int sadclose(queue_t *, int, cred_t *); 600Sstevel@tonic-gate static int sadwput(queue_t *qp, mblk_t *mp); 610Sstevel@tonic-gate 620Sstevel@tonic-gate static int sad_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 630Sstevel@tonic-gate static int sad_attach(dev_info_t *, ddi_attach_cmd_t); 640Sstevel@tonic-gate 650Sstevel@tonic-gate static void apush_ioctl(), apush_iocdata(); 660Sstevel@tonic-gate static void vml_ioctl(), vml_iocdata(); 670Sstevel@tonic-gate static int valid_major(major_t); 680Sstevel@tonic-gate 690Sstevel@tonic-gate static dev_info_t *sad_dip; /* private copy of devinfo pointer */ 700Sstevel@tonic-gate 710Sstevel@tonic-gate static struct module_info sad_minfo = { 720Sstevel@tonic-gate 0x7361, "sad", 0, INFPSZ, 0, 0 730Sstevel@tonic-gate }; 740Sstevel@tonic-gate 750Sstevel@tonic-gate static struct qinit sad_rinit = { 760Sstevel@tonic-gate NULL, NULL, sadopen, sadclose, NULL, &sad_minfo, NULL 770Sstevel@tonic-gate }; 780Sstevel@tonic-gate 790Sstevel@tonic-gate static struct qinit sad_winit = { 800Sstevel@tonic-gate sadwput, NULL, NULL, NULL, NULL, &sad_minfo, NULL 810Sstevel@tonic-gate }; 820Sstevel@tonic-gate 830Sstevel@tonic-gate struct streamtab sadinfo = { 840Sstevel@tonic-gate &sad_rinit, &sad_winit, NULL, NULL 850Sstevel@tonic-gate }; 860Sstevel@tonic-gate 870Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(sad_ops, nulldev, nulldev, sad_attach, 883042Sedp nodev, nodev, sad_info, D_MTPERQ | D_MP, &sadinfo); 890Sstevel@tonic-gate 900Sstevel@tonic-gate /* 910Sstevel@tonic-gate * Module linkage information for the kernel. 920Sstevel@tonic-gate */ 930Sstevel@tonic-gate 940Sstevel@tonic-gate static struct modldrv modldrv = { 950Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 960Sstevel@tonic-gate "STREAMS Administrative Driver 'sad' %I%", 970Sstevel@tonic-gate &sad_ops, /* driver ops */ 980Sstevel@tonic-gate }; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate static struct modlinkage modlinkage = { 1010Sstevel@tonic-gate MODREV_1, &modldrv, NULL 1020Sstevel@tonic-gate }; 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate int 1050Sstevel@tonic-gate _init(void) 1060Sstevel@tonic-gate { 1070Sstevel@tonic-gate return (mod_install(&modlinkage)); 1080Sstevel@tonic-gate } 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate int 1110Sstevel@tonic-gate _fini(void) 1120Sstevel@tonic-gate { 1130Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate int 1170Sstevel@tonic-gate _info(struct modinfo *modinfop) 1180Sstevel@tonic-gate { 1190Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1200Sstevel@tonic-gate } 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate static int 1230Sstevel@tonic-gate sad_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 1240Sstevel@tonic-gate { 1253042Sedp int instance = ddi_get_instance(devi); 1263042Sedp 1270Sstevel@tonic-gate if (cmd != DDI_ATTACH) 1280Sstevel@tonic-gate return (DDI_FAILURE); 1290Sstevel@tonic-gate 1303042Sedp ASSERT(instance == 0); 1313042Sedp if (instance != 0) 1323042Sedp return (DDI_FAILURE); 1333042Sedp 1340Sstevel@tonic-gate if (ddi_create_minor_node(devi, "user", S_IFCHR, 1350Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 1360Sstevel@tonic-gate return (DDI_FAILURE); 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate if (ddi_create_priv_minor_node(devi, "admin", S_IFCHR, 1390Sstevel@tonic-gate 1, DDI_PSEUDO, PRIVONLY_DEV, PRIV_SYS_CONFIG, 1400Sstevel@tonic-gate PRIV_SYS_CONFIG, 0666) == DDI_FAILURE) { 1410Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 1420Sstevel@tonic-gate return (DDI_FAILURE); 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate sad_dip = devi; 1450Sstevel@tonic-gate return (DDI_SUCCESS); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate /* ARGSUSED */ 1490Sstevel@tonic-gate static int 1500Sstevel@tonic-gate sad_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 1510Sstevel@tonic-gate { 1520Sstevel@tonic-gate int error; 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate switch (infocmd) { 1550Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 1560Sstevel@tonic-gate if (sad_dip == NULL) { 1570Sstevel@tonic-gate error = DDI_FAILURE; 1580Sstevel@tonic-gate } else { 1590Sstevel@tonic-gate *result = sad_dip; 1600Sstevel@tonic-gate error = DDI_SUCCESS; 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate break; 1630Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 1640Sstevel@tonic-gate *result = (void *)0; 1650Sstevel@tonic-gate error = DDI_SUCCESS; 1660Sstevel@tonic-gate break; 1670Sstevel@tonic-gate default: 1680Sstevel@tonic-gate error = DDI_FAILURE; 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate return (error); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate /* 1750Sstevel@tonic-gate * sadopen() - 1760Sstevel@tonic-gate * Allocate a sad device. Only one 1770Sstevel@tonic-gate * open at a time allowed per device. 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate /* ARGSUSED */ 1800Sstevel@tonic-gate static int 1810Sstevel@tonic-gate sadopen( 1820Sstevel@tonic-gate queue_t *qp, /* pointer to read queue */ 1830Sstevel@tonic-gate dev_t *devp, /* major/minor device of stream */ 1840Sstevel@tonic-gate int flag, /* file open flags */ 1850Sstevel@tonic-gate int sflag, /* stream open flags */ 1860Sstevel@tonic-gate cred_t *credp) /* user credentials */ 1870Sstevel@tonic-gate { 1880Sstevel@tonic-gate int i; 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate if (sflag) /* no longer called from clone driver */ 1910Sstevel@tonic-gate return (EINVAL); 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate /* 1940Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces. 1950Sstevel@tonic-gate */ 1960Sstevel@tonic-gate for (i = 0; i < sadcnt; i++) 1970Sstevel@tonic-gate if (saddev[i].sa_qp == NULL) 1980Sstevel@tonic-gate break; 1990Sstevel@tonic-gate if (i >= sadcnt) /* no such device */ 2000Sstevel@tonic-gate return (ENXIO); 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate switch (getminor(*devp)) { 2030Sstevel@tonic-gate case USRMIN: /* mere mortal */ 2040Sstevel@tonic-gate saddev[i].sa_flags = 0; 2050Sstevel@tonic-gate break; 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate case ADMMIN: /* privileged user */ 2080Sstevel@tonic-gate saddev[i].sa_flags = SADPRIV; 2090Sstevel@tonic-gate break; 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate default: 2120Sstevel@tonic-gate return (EINVAL); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate saddev[i].sa_qp = qp; 2160Sstevel@tonic-gate qp->q_ptr = (caddr_t)&saddev[i]; 2170Sstevel@tonic-gate WR(qp)->q_ptr = (caddr_t)&saddev[i]; 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate /* 2200Sstevel@tonic-gate * NOTE: should the ADMMIN or USRMIN minors change 2210Sstevel@tonic-gate * then so should the offset of 2 below 2220Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces and 2230Sstevel@tonic-gate * therefore their minor numbers (0 and 1) are reserved. 2240Sstevel@tonic-gate */ 2250Sstevel@tonic-gate *devp = makedevice(getemajor(*devp), i + 2); 2260Sstevel@tonic-gate qprocson(qp); 2270Sstevel@tonic-gate return (0); 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* 2310Sstevel@tonic-gate * sadclose() - 2320Sstevel@tonic-gate * Clean up the data structures. 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate /* ARGSUSED */ 2350Sstevel@tonic-gate static int 2360Sstevel@tonic-gate sadclose( 2370Sstevel@tonic-gate queue_t *qp, /* pointer to read queue */ 2380Sstevel@tonic-gate int flag, /* file open flags */ 2390Sstevel@tonic-gate cred_t *credp) /* user credentials */ 2400Sstevel@tonic-gate { 2410Sstevel@tonic-gate struct saddev *sadp; 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate qprocsoff(qp); 2440Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 2450Sstevel@tonic-gate sadp->sa_qp = NULL; 2460Sstevel@tonic-gate sadp->sa_addr = NULL; 2470Sstevel@tonic-gate qp->q_ptr = NULL; 2480Sstevel@tonic-gate WR(qp)->q_ptr = NULL; 2490Sstevel@tonic-gate return (0); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * sadwput() - 2540Sstevel@tonic-gate * Write side put procedure. 2550Sstevel@tonic-gate */ 2560Sstevel@tonic-gate static int 2570Sstevel@tonic-gate sadwput( 2580Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 2590Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 2600Sstevel@tonic-gate { 2610Sstevel@tonic-gate struct iocblk *iocp; 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate switch (mp->b_datap->db_type) { 2640Sstevel@tonic-gate case M_FLUSH: 2650Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 2660Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 2670Sstevel@tonic-gate qreply(qp, mp); 2680Sstevel@tonic-gate } else 2690Sstevel@tonic-gate freemsg(mp); 2700Sstevel@tonic-gate break; 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate case M_IOCTL: 2730Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 2740Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 2750Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 2760Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 2770Sstevel@tonic-gate apush_ioctl(qp, mp); 2780Sstevel@tonic-gate break; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate case SAD_VML: 2810Sstevel@tonic-gate vml_ioctl(qp, mp); 2820Sstevel@tonic-gate break; 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate default: 2850Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 2860Sstevel@tonic-gate break; 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate break; 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate case M_IOCDATA: 2910Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 2920Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 2930Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 2940Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 2950Sstevel@tonic-gate apush_iocdata(qp, mp); 2960Sstevel@tonic-gate break; 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate case SAD_VML: 2990Sstevel@tonic-gate vml_iocdata(qp, mp); 3000Sstevel@tonic-gate break; 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate default: 3030Sstevel@tonic-gate cmn_err(CE_WARN, 3040Sstevel@tonic-gate "sadwput: invalid ioc_cmd in case M_IOCDATA: %d", 3050Sstevel@tonic-gate iocp->ioc_cmd); 3060Sstevel@tonic-gate freemsg(mp); 3070Sstevel@tonic-gate break; 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate break; 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate default: 3120Sstevel@tonic-gate freemsg(mp); 3130Sstevel@tonic-gate break; 3140Sstevel@tonic-gate } /* switch (db_type) */ 3150Sstevel@tonic-gate return (0); 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate /* 3190Sstevel@tonic-gate * apush_ioctl() - 3200Sstevel@tonic-gate * Handle the M_IOCTL messages associated with 3210Sstevel@tonic-gate * the autopush feature. 3220Sstevel@tonic-gate */ 3230Sstevel@tonic-gate static void 3240Sstevel@tonic-gate apush_ioctl( 3250Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 3260Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 3270Sstevel@tonic-gate { 3280Sstevel@tonic-gate struct iocblk *iocp; 3290Sstevel@tonic-gate struct saddev *sadp; 3300Sstevel@tonic-gate uint_t size; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3330Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 3340Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3350Sstevel@tonic-gate return; 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) > AP_VERSION) { 3380Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3390Sstevel@tonic-gate return; 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 3430Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 3440Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 3450Sstevel@tonic-gate if (!(sadp->sa_flags & SADPRIV)) { 3460Sstevel@tonic-gate miocnak(qp, mp, 0, EPERM); 3470Sstevel@tonic-gate break; 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate /* FALLTHRU */ 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 3520Sstevel@tonic-gate sadp->sa_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 3530Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) == 1) 3540Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 3550Sstevel@tonic-gate else 3560Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 3570Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, size, NULL); 3580Sstevel@tonic-gate qreply(qp, mp); 3590Sstevel@tonic-gate break; 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate default: 3620Sstevel@tonic-gate ASSERT(0); 3630Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3640Sstevel@tonic-gate break; 3650Sstevel@tonic-gate } /* switch (ioc_cmd) */ 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate /* 3690Sstevel@tonic-gate * apush_iocdata() - 3700Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 3710Sstevel@tonic-gate * the autopush feature. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate static void 3740Sstevel@tonic-gate apush_iocdata( 3750Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 3760Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 3770Sstevel@tonic-gate { 3780Sstevel@tonic-gate int i, ret; 3790Sstevel@tonic-gate struct copyresp *csp; 3803064Sedp struct strapush *sap = NULL; 3813042Sedp struct autopush *ap, *ap_tmp; 3820Sstevel@tonic-gate struct saddev *sadp; 3830Sstevel@tonic-gate uint_t size; 3843042Sedp dev_t dev; 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 3870Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 3880Sstevel@tonic-gate freemsg(mp); 3890Sstevel@tonic-gate return; 3900Sstevel@tonic-gate } 3913042Sedp if (mp->b_cont) { 3923042Sedp /* 3933064Sedp * sap needed only if mp->b_cont is set. figure out the 3943064Sedp * size of the expected sap structure and make sure 3953064Sedp * enough data was supplied. 3963042Sedp */ 3973064Sedp if (SAD_VER(csp->cp_cmd) == 1) 3983064Sedp size = STRAPUSH_V1_LEN; 3993064Sedp else 4003064Sedp size = STRAPUSH_V0_LEN; 4013064Sedp if (MBLKL(mp->b_cont) < size) { 4023064Sedp miocnak(qp, mp, 0, EINVAL); 4033042Sedp return; 4043042Sedp } 4050Sstevel@tonic-gate sap = (struct strapush *)mp->b_cont->b_rptr; 4063042Sedp dev = makedevice(sap->sap_major, sap->sap_minor); 4073042Sedp } 4080Sstevel@tonic-gate switch (SAD_CMD(csp->cp_cmd)) { 4090Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 4100Sstevel@tonic-gate 4113042Sedp /* currently we only support one SAD_SAP command */ 4123042Sedp if (((long)csp->cp_private) != GETSTRUCT) { 4130Sstevel@tonic-gate cmn_err(CE_WARN, 4140Sstevel@tonic-gate "apush_iocdata: cp_private bad in SAD_SAP: %p", 4150Sstevel@tonic-gate (void *)csp->cp_private); 4163042Sedp miocnak(qp, mp, 0, EINVAL); 4173042Sedp return; 4183042Sedp } 4193042Sedp 4203042Sedp switch (sap->sap_cmd) { 4213042Sedp default: 4223042Sedp miocnak(qp, mp, 0, EINVAL); 4233042Sedp return; 4243042Sedp case SAP_ONE: 4253042Sedp case SAP_RANGE: 4263042Sedp case SAP_ALL: 4273042Sedp /* allocate and initialize a new config */ 4283042Sedp ap = sad_ap_alloc(); 4293042Sedp ap->ap_common = sap->sap_common; 4303042Sedp if (SAD_VER(csp->cp_cmd) > 0) 4313042Sedp ap->ap_anchor = sap->sap_anchor; 4323042Sedp for (i = 0; i < MIN(sap->sap_npush, MAXAPUSH); i++) 4333042Sedp (void) strncpy(ap->ap_list[i], 4343042Sedp sap->sap_list[i], FMNAMESZ); 4353042Sedp 4363042Sedp /* sanity check the request */ 4373042Sedp if (((ret = sad_ap_verify(ap)) != 0) || 4383042Sedp ((ret = valid_major(ap->ap_major)) != 0)) { 4393042Sedp sad_ap_rele(ap); 4403042Sedp miocnak(qp, mp, 0, ret); 4413042Sedp return; 4423042Sedp } 4433042Sedp 4443042Sedp /* check for overlapping configs */ 4453042Sedp mutex_enter(&sad_lock); 4463042Sedp if ((ap_tmp = sad_ap_find(&ap->ap_common)) != NULL) { 4473042Sedp /* already configured */ 4483042Sedp mutex_exit(&sad_lock); 4493042Sedp sad_ap_rele(ap_tmp); 4503042Sedp sad_ap_rele(ap); 4513042Sedp miocnak(qp, mp, 0, EEXIST); 4523042Sedp return; 4533042Sedp } 4543042Sedp 4553042Sedp /* add the new config to our hash */ 4563042Sedp sad_ap_insert(ap); 4573042Sedp mutex_exit(&sad_lock); 4583042Sedp miocack(qp, mp, 0, 0); 4593042Sedp return; 4603042Sedp 4613042Sedp case SAP_CLEAR: 4623042Sedp /* sanity check the request */ 4633042Sedp if (ret = valid_major(sap->sap_major)) { 4643042Sedp miocnak(qp, mp, 0, ret); 4653042Sedp return; 4663042Sedp } 4673042Sedp 4683042Sedp /* search for a matching config */ 4693042Sedp if ((ap = sad_ap_find_by_dev(dev)) == NULL) { 4703042Sedp /* no config found */ 4713042Sedp miocnak(qp, mp, 0, ENODEV); 4723042Sedp return; 4733042Sedp } 4743042Sedp 4753042Sedp /* 4763042Sedp * If we matched a SAP_RANGE config 4773042Sedp * the minor passed in must match the 4783042Sedp * beginning of the range exactly. 4793042Sedp */ 4803042Sedp if ((ap->ap_type == SAP_RANGE) && 4813042Sedp (ap->ap_minor != sap->sap_minor)) { 4823042Sedp sad_ap_rele(ap); 4833042Sedp miocnak(qp, mp, 0, ERANGE); 4843042Sedp return; 4853042Sedp } 4863042Sedp 4873042Sedp /* 4883042Sedp * If we matched a SAP_ALL config 4893042Sedp * the minor passed in must be 0. 4903042Sedp */ 4913042Sedp if ((ap->ap_type == SAP_ALL) && 4923042Sedp (sap->sap_minor != 0)) { 4933042Sedp sad_ap_rele(ap); 4943042Sedp miocnak(qp, mp, 0, EINVAL); 4953042Sedp return; 4963042Sedp } 4973042Sedp 4983042Sedp /* 4993042Sedp * make sure someone else hasn't already 5003042Sedp * removed this config from the hash. 5013042Sedp */ 5023042Sedp mutex_enter(&sad_lock); 5033042Sedp ap_tmp = sad_ap_find(&ap->ap_common); 5043042Sedp if (ap_tmp != ap) { 5053042Sedp mutex_exit(&sad_lock); 5063042Sedp sad_ap_rele(ap_tmp); 5073042Sedp sad_ap_rele(ap); 5083042Sedp miocnak(qp, mp, 0, ENODEV); 5093042Sedp return; 5103042Sedp } else 5113042Sedp 5123042Sedp /* remove the config from the hash and return */ 5133042Sedp sad_ap_remove(ap); 5143042Sedp mutex_exit(&sad_lock); 5153042Sedp 5163042Sedp /* 5173042Sedp * Release thrice, once for sad_ap_find_by_dev(), 5183042Sedp * once for sad_ap_find(), and once to free. 5193042Sedp */ 5203042Sedp sad_ap_rele(ap); 5213042Sedp sad_ap_rele(ap); 5223042Sedp sad_ap_rele(ap); 5233042Sedp miocack(qp, mp, 0, 0); 5243042Sedp return; 5253042Sedp } /* switch (sap_cmd) */ 5263042Sedp /*NOTREACHED*/ 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 5290Sstevel@tonic-gate switch ((long)csp->cp_private) { 5300Sstevel@tonic-gate 5313042Sedp case GETSTRUCT: 5323042Sedp /* sanity check the request */ 5330Sstevel@tonic-gate if (ret = valid_major(sap->sap_major)) { 5340Sstevel@tonic-gate miocnak(qp, mp, 0, ret); 5353042Sedp return; 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 5383042Sedp /* search for a matching config */ 5393042Sedp if ((ap = sad_ap_find_by_dev(dev)) == NULL) { 5403042Sedp /* no config found */ 5413042Sedp miocnak(qp, mp, 0, ENODEV); 5423042Sedp return; 5433042Sedp } 5443042Sedp 5453042Sedp /* copy out the contents of the config */ 5460Sstevel@tonic-gate sap->sap_common = ap->ap_common; 5470Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) > 0) 5480Sstevel@tonic-gate sap->sap_anchor = ap->ap_anchor; 5490Sstevel@tonic-gate for (i = 0; i < ap->ap_npush; i++) 5500Sstevel@tonic-gate (void) strcpy(sap->sap_list[i], ap->ap_list[i]); 5510Sstevel@tonic-gate for (; i < MAXAPUSH; i++) 5520Sstevel@tonic-gate bzero(sap->sap_list[i], FMNAMESZ + 1); 5530Sstevel@tonic-gate 5543042Sedp /* release our hold on the config */ 5553042Sedp sad_ap_rele(ap); 5563042Sedp 5573042Sedp /* copyout the results */ 5580Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) == 1) 5590Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 5600Sstevel@tonic-gate else 5610Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 5640Sstevel@tonic-gate mcopyout(mp, (void *)GETRESULT, size, sadp->sa_addr, 5650Sstevel@tonic-gate NULL); 5660Sstevel@tonic-gate qreply(qp, mp); 5673042Sedp return; 5680Sstevel@tonic-gate case GETRESULT: 5690Sstevel@tonic-gate miocack(qp, mp, 0, 0); 5703042Sedp return; 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate default: 5730Sstevel@tonic-gate cmn_err(CE_WARN, 5740Sstevel@tonic-gate "apush_iocdata: cp_private bad case SAD_GAP: %p", 5750Sstevel@tonic-gate (void *)csp->cp_private); 5760Sstevel@tonic-gate freemsg(mp); 5773042Sedp return; 5780Sstevel@tonic-gate } /* switch (cp_private) */ 5793042Sedp /*NOTREACHED*/ 5800Sstevel@tonic-gate default: /* can't happen */ 5810Sstevel@tonic-gate ASSERT(0); 5820Sstevel@tonic-gate freemsg(mp); 5833042Sedp return; 5840Sstevel@tonic-gate } /* switch (cp_cmd) */ 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate /* 5880Sstevel@tonic-gate * vml_ioctl() - 5890Sstevel@tonic-gate * Handle the M_IOCTL message associated with a request 5900Sstevel@tonic-gate * to validate a module list. 5910Sstevel@tonic-gate */ 5920Sstevel@tonic-gate static void 5930Sstevel@tonic-gate vml_ioctl( 5940Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 5950Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 5960Sstevel@tonic-gate { 5970Sstevel@tonic-gate struct iocblk *iocp; 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 6000Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 6010Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 6020Sstevel@tonic-gate return; 6030Sstevel@tonic-gate } 604*3324Sethindra ASSERT(SAD_CMD(iocp->ioc_cmd) == SAD_VML); 6050Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, 6060Sstevel@tonic-gate SIZEOF_STRUCT(str_list, iocp->ioc_flag), NULL); 6070Sstevel@tonic-gate qreply(qp, mp); 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate /* 6110Sstevel@tonic-gate * vml_iocdata() - 6120Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 6130Sstevel@tonic-gate * a request to validate a module list. 6140Sstevel@tonic-gate */ 6150Sstevel@tonic-gate static void 6160Sstevel@tonic-gate vml_iocdata( 6170Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 6180Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 6190Sstevel@tonic-gate { 6200Sstevel@tonic-gate long i; 6210Sstevel@tonic-gate int nmods; 6220Sstevel@tonic-gate struct copyresp *csp; 6230Sstevel@tonic-gate struct str_mlist *lp; 6240Sstevel@tonic-gate STRUCT_HANDLE(str_list, slp); 6250Sstevel@tonic-gate struct saddev *sadp; 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 6280Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 6290Sstevel@tonic-gate freemsg(mp); 6300Sstevel@tonic-gate return; 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate 633*3324Sethindra ASSERT(SAD_CMD(csp->cp_cmd) == SAD_VML); 6340Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 6350Sstevel@tonic-gate switch ((long)csp->cp_private) { 6360Sstevel@tonic-gate case GETSTRUCT: 6370Sstevel@tonic-gate STRUCT_SET_HANDLE(slp, csp->cp_flag, 6380Sstevel@tonic-gate (struct str_list *)mp->b_cont->b_rptr); 6390Sstevel@tonic-gate nmods = STRUCT_FGET(slp, sl_nmods); 6400Sstevel@tonic-gate if (nmods <= 0) { 6410Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 6420Sstevel@tonic-gate break; 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate sadp->sa_addr = (caddr_t)(uintptr_t)nmods; 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate mcopyin(mp, (void *)GETLIST, nmods * sizeof (struct str_mlist), 6470Sstevel@tonic-gate STRUCT_FGETP(slp, sl_modlist)); 6480Sstevel@tonic-gate qreply(qp, mp); 6490Sstevel@tonic-gate break; 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate case GETLIST: 6520Sstevel@tonic-gate lp = (struct str_mlist *)mp->b_cont->b_rptr; 6530Sstevel@tonic-gate for (i = 0; i < (long)sadp->sa_addr; i++, lp++) { 6540Sstevel@tonic-gate lp->l_name[FMNAMESZ] = '\0'; 6550Sstevel@tonic-gate if (fmodsw_find(lp->l_name, FMODSW_LOAD) == NULL) { 6560Sstevel@tonic-gate miocack(qp, mp, 0, 1); 6570Sstevel@tonic-gate return; 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate miocack(qp, mp, 0, 0); 6610Sstevel@tonic-gate break; 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate default: 6640Sstevel@tonic-gate cmn_err(CE_WARN, "vml_iocdata: invalid cp_private value: %p", 6650Sstevel@tonic-gate (void *)csp->cp_private); 6660Sstevel@tonic-gate freemsg(mp); 6670Sstevel@tonic-gate break; 6680Sstevel@tonic-gate } /* switch (cp_private) */ 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate /* 6720Sstevel@tonic-gate * Validate a major number and also verify if 6730Sstevel@tonic-gate * it is a STREAMS device. 6740Sstevel@tonic-gate * Return values: 0 if a valid STREAMS dev 6750Sstevel@tonic-gate * error code otherwise 6760Sstevel@tonic-gate */ 6770Sstevel@tonic-gate static int 6780Sstevel@tonic-gate valid_major(major_t major) 6790Sstevel@tonic-gate { 6800Sstevel@tonic-gate int ret = 0; 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate if (etoimajor(major) == -1) 6830Sstevel@tonic-gate return (EINVAL); 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * attempt to load the driver 'major' and verify that 6870Sstevel@tonic-gate * it is a STREAMS driver. 6880Sstevel@tonic-gate */ 6890Sstevel@tonic-gate if (ddi_hold_driver(major) == NULL) 6900Sstevel@tonic-gate return (EINVAL); 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate if (!STREAMSTAB(major)) 6930Sstevel@tonic-gate ret = ENOSTR; 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate ddi_rele_driver(major); 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate return (ret); 6980Sstevel@tonic-gate } 699