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 /* 223448Sdh155122 * Copyright 2007 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> 553042Sedp #include <sys/sysmacros.h> 563448Sdh155122 #include <sys/zone.h> 57*4962Sdh155122 #include <sys/policy.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate static int sadopen(queue_t *, dev_t *, int, int, cred_t *); 600Sstevel@tonic-gate static int sadclose(queue_t *, int, cred_t *); 610Sstevel@tonic-gate static int sadwput(queue_t *qp, mblk_t *mp); 620Sstevel@tonic-gate 630Sstevel@tonic-gate static int sad_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 640Sstevel@tonic-gate static int sad_attach(dev_info_t *, ddi_attach_cmd_t); 650Sstevel@tonic-gate 660Sstevel@tonic-gate static void apush_ioctl(), apush_iocdata(); 670Sstevel@tonic-gate static void vml_ioctl(), vml_iocdata(); 680Sstevel@tonic-gate static int valid_major(major_t); 690Sstevel@tonic-gate 700Sstevel@tonic-gate static dev_info_t *sad_dip; /* private copy of devinfo pointer */ 710Sstevel@tonic-gate 720Sstevel@tonic-gate static struct module_info sad_minfo = { 730Sstevel@tonic-gate 0x7361, "sad", 0, INFPSZ, 0, 0 740Sstevel@tonic-gate }; 750Sstevel@tonic-gate 760Sstevel@tonic-gate static struct qinit sad_rinit = { 770Sstevel@tonic-gate NULL, NULL, sadopen, sadclose, NULL, &sad_minfo, NULL 780Sstevel@tonic-gate }; 790Sstevel@tonic-gate 800Sstevel@tonic-gate static struct qinit sad_winit = { 810Sstevel@tonic-gate sadwput, NULL, NULL, NULL, NULL, &sad_minfo, NULL 820Sstevel@tonic-gate }; 830Sstevel@tonic-gate 840Sstevel@tonic-gate struct streamtab sadinfo = { 850Sstevel@tonic-gate &sad_rinit, &sad_winit, NULL, NULL 860Sstevel@tonic-gate }; 870Sstevel@tonic-gate 880Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(sad_ops, nulldev, nulldev, sad_attach, 894294Sjfrank nodev, nodev, sad_info, 904294Sjfrank D_MP | D_MTPERQ | D_MTOUTPERIM | D_MTOCEXCL, &sadinfo); 910Sstevel@tonic-gate 920Sstevel@tonic-gate /* 930Sstevel@tonic-gate * Module linkage information for the kernel. 940Sstevel@tonic-gate */ 950Sstevel@tonic-gate 960Sstevel@tonic-gate static struct modldrv modldrv = { 970Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 98*4962Sdh155122 "STREAMS Administrative Driver 'sad'", 990Sstevel@tonic-gate &sad_ops, /* driver ops */ 1000Sstevel@tonic-gate }; 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate static struct modlinkage modlinkage = { 1030Sstevel@tonic-gate MODREV_1, &modldrv, NULL 1040Sstevel@tonic-gate }; 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate int 1070Sstevel@tonic-gate _init(void) 1080Sstevel@tonic-gate { 1090Sstevel@tonic-gate return (mod_install(&modlinkage)); 1100Sstevel@tonic-gate } 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate int 1130Sstevel@tonic-gate _fini(void) 1140Sstevel@tonic-gate { 1150Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate int 1190Sstevel@tonic-gate _info(struct modinfo *modinfop) 1200Sstevel@tonic-gate { 1210Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate static int 1250Sstevel@tonic-gate sad_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 1260Sstevel@tonic-gate { 1273042Sedp int instance = ddi_get_instance(devi); 1283042Sedp 1290Sstevel@tonic-gate if (cmd != DDI_ATTACH) 1300Sstevel@tonic-gate return (DDI_FAILURE); 1310Sstevel@tonic-gate 1323042Sedp ASSERT(instance == 0); 1333042Sedp if (instance != 0) 1343042Sedp return (DDI_FAILURE); 1353042Sedp 1360Sstevel@tonic-gate if (ddi_create_minor_node(devi, "user", S_IFCHR, 1370Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 1380Sstevel@tonic-gate return (DDI_FAILURE); 1390Sstevel@tonic-gate } 140*4962Sdh155122 if (ddi_create_minor_node(devi, "admin", S_IFCHR, 141*4962Sdh155122 1, DDI_PSEUDO, NULL) == DDI_FAILURE) { 1420Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 1430Sstevel@tonic-gate return (DDI_FAILURE); 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate sad_dip = devi; 1460Sstevel@tonic-gate return (DDI_SUCCESS); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate /* ARGSUSED */ 1500Sstevel@tonic-gate static int 1510Sstevel@tonic-gate sad_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 1520Sstevel@tonic-gate { 1530Sstevel@tonic-gate int error; 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate switch (infocmd) { 1560Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 1570Sstevel@tonic-gate if (sad_dip == NULL) { 1580Sstevel@tonic-gate error = DDI_FAILURE; 1590Sstevel@tonic-gate } else { 1600Sstevel@tonic-gate *result = sad_dip; 1610Sstevel@tonic-gate error = DDI_SUCCESS; 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate break; 1640Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 1650Sstevel@tonic-gate *result = (void *)0; 1660Sstevel@tonic-gate error = DDI_SUCCESS; 1670Sstevel@tonic-gate break; 1680Sstevel@tonic-gate default: 1690Sstevel@tonic-gate error = DDI_FAILURE; 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate return (error); 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate /* 1760Sstevel@tonic-gate * sadopen() - 1770Sstevel@tonic-gate * Allocate a sad device. Only one 1780Sstevel@tonic-gate * open at a time allowed per device. 1790Sstevel@tonic-gate */ 1800Sstevel@tonic-gate /* ARGSUSED */ 1810Sstevel@tonic-gate static int 1820Sstevel@tonic-gate sadopen( 1830Sstevel@tonic-gate queue_t *qp, /* pointer to read queue */ 1840Sstevel@tonic-gate dev_t *devp, /* major/minor device of stream */ 1850Sstevel@tonic-gate int flag, /* file open flags */ 1860Sstevel@tonic-gate int sflag, /* stream open flags */ 1870Sstevel@tonic-gate cred_t *credp) /* user credentials */ 1880Sstevel@tonic-gate { 1890Sstevel@tonic-gate int i; 1903448Sdh155122 netstack_t *ns; 1913448Sdh155122 str_stack_t *ss; 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate if (sflag) /* no longer called from clone driver */ 1940Sstevel@tonic-gate return (EINVAL); 1950Sstevel@tonic-gate 196*4962Sdh155122 /* Only privileged process can access ADMINDEV */ 197*4962Sdh155122 if (getminor(*devp) == ADMMIN) { 198*4962Sdh155122 int err; 199*4962Sdh155122 200*4962Sdh155122 err = secpolicy_sadopen(credp); 201*4962Sdh155122 202*4962Sdh155122 if (err != 0) 203*4962Sdh155122 return (err); 204*4962Sdh155122 } 205*4962Sdh155122 2063448Sdh155122 ns = netstack_find_by_cred(credp); 2073448Sdh155122 ASSERT(ns != NULL); 2083448Sdh155122 ss = ns->netstack_str; 2093448Sdh155122 ASSERT(ss != NULL); 2103448Sdh155122 2110Sstevel@tonic-gate /* 2120Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces. 2130Sstevel@tonic-gate */ 2143448Sdh155122 for (i = 0; i < ss->ss_sadcnt; i++) 2153448Sdh155122 if (ss->ss_saddev[i].sa_qp == NULL) 2160Sstevel@tonic-gate break; 2173448Sdh155122 if (i >= ss->ss_sadcnt) { /* no such device */ 2183448Sdh155122 netstack_rele(ss->ss_netstack); 2190Sstevel@tonic-gate return (ENXIO); 2203448Sdh155122 } 2210Sstevel@tonic-gate switch (getminor(*devp)) { 2220Sstevel@tonic-gate case USRMIN: /* mere mortal */ 2233448Sdh155122 ss->ss_saddev[i].sa_flags = 0; 2240Sstevel@tonic-gate break; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate case ADMMIN: /* privileged user */ 2273448Sdh155122 ss->ss_saddev[i].sa_flags = SADPRIV; 2280Sstevel@tonic-gate break; 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate default: 2313448Sdh155122 netstack_rele(ss->ss_netstack); 2320Sstevel@tonic-gate return (EINVAL); 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 2353448Sdh155122 ss->ss_saddev[i].sa_qp = qp; 2363448Sdh155122 ss->ss_saddev[i].sa_ss = ss; 2373448Sdh155122 qp->q_ptr = (caddr_t)&ss->ss_saddev[i]; 2383448Sdh155122 WR(qp)->q_ptr = (caddr_t)&ss->ss_saddev[i]; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate /* 2410Sstevel@tonic-gate * NOTE: should the ADMMIN or USRMIN minors change 2420Sstevel@tonic-gate * then so should the offset of 2 below 2430Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces and 2440Sstevel@tonic-gate * therefore their minor numbers (0 and 1) are reserved. 2450Sstevel@tonic-gate */ 2460Sstevel@tonic-gate *devp = makedevice(getemajor(*devp), i + 2); 2470Sstevel@tonic-gate qprocson(qp); 2480Sstevel@tonic-gate return (0); 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate /* 2520Sstevel@tonic-gate * sadclose() - 2530Sstevel@tonic-gate * Clean up the data structures. 2540Sstevel@tonic-gate */ 2550Sstevel@tonic-gate /* ARGSUSED */ 2560Sstevel@tonic-gate static int 2570Sstevel@tonic-gate sadclose( 2580Sstevel@tonic-gate queue_t *qp, /* pointer to read queue */ 2590Sstevel@tonic-gate int flag, /* file open flags */ 2600Sstevel@tonic-gate cred_t *credp) /* user credentials */ 2610Sstevel@tonic-gate { 2620Sstevel@tonic-gate struct saddev *sadp; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate qprocsoff(qp); 2650Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 2660Sstevel@tonic-gate sadp->sa_qp = NULL; 2670Sstevel@tonic-gate sadp->sa_addr = NULL; 2683448Sdh155122 netstack_rele(sadp->sa_ss->ss_netstack); 2693448Sdh155122 sadp->sa_ss = NULL; 2700Sstevel@tonic-gate qp->q_ptr = NULL; 2710Sstevel@tonic-gate WR(qp)->q_ptr = NULL; 2720Sstevel@tonic-gate return (0); 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate /* 2760Sstevel@tonic-gate * sadwput() - 2770Sstevel@tonic-gate * Write side put procedure. 2780Sstevel@tonic-gate */ 2790Sstevel@tonic-gate static int 2800Sstevel@tonic-gate sadwput( 2810Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 2820Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 2830Sstevel@tonic-gate { 2840Sstevel@tonic-gate struct iocblk *iocp; 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate switch (mp->b_datap->db_type) { 2870Sstevel@tonic-gate case M_FLUSH: 2880Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 2890Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 2900Sstevel@tonic-gate qreply(qp, mp); 2910Sstevel@tonic-gate } else 2920Sstevel@tonic-gate freemsg(mp); 2930Sstevel@tonic-gate break; 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate case M_IOCTL: 2960Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 2970Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 2980Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 2990Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 3000Sstevel@tonic-gate apush_ioctl(qp, mp); 3010Sstevel@tonic-gate break; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate case SAD_VML: 3040Sstevel@tonic-gate vml_ioctl(qp, mp); 3050Sstevel@tonic-gate break; 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate default: 3080Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3090Sstevel@tonic-gate break; 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate break; 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate case M_IOCDATA: 3140Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3150Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 3160Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 3170Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 3180Sstevel@tonic-gate apush_iocdata(qp, mp); 3190Sstevel@tonic-gate break; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate case SAD_VML: 3220Sstevel@tonic-gate vml_iocdata(qp, mp); 3230Sstevel@tonic-gate break; 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate default: 3260Sstevel@tonic-gate cmn_err(CE_WARN, 3270Sstevel@tonic-gate "sadwput: invalid ioc_cmd in case M_IOCDATA: %d", 3280Sstevel@tonic-gate iocp->ioc_cmd); 3290Sstevel@tonic-gate freemsg(mp); 3300Sstevel@tonic-gate break; 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate break; 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate default: 3350Sstevel@tonic-gate freemsg(mp); 3360Sstevel@tonic-gate break; 3370Sstevel@tonic-gate } /* switch (db_type) */ 3380Sstevel@tonic-gate return (0); 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* 3420Sstevel@tonic-gate * apush_ioctl() - 3430Sstevel@tonic-gate * Handle the M_IOCTL messages associated with 3440Sstevel@tonic-gate * the autopush feature. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate static void 3470Sstevel@tonic-gate apush_ioctl( 3480Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 3490Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 3500Sstevel@tonic-gate { 3510Sstevel@tonic-gate struct iocblk *iocp; 3520Sstevel@tonic-gate struct saddev *sadp; 3530Sstevel@tonic-gate uint_t size; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3560Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 3570Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3580Sstevel@tonic-gate return; 3590Sstevel@tonic-gate } 3600Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) > AP_VERSION) { 3610Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3620Sstevel@tonic-gate return; 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 3660Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 3670Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 3680Sstevel@tonic-gate if (!(sadp->sa_flags & SADPRIV)) { 3690Sstevel@tonic-gate miocnak(qp, mp, 0, EPERM); 3700Sstevel@tonic-gate break; 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate /* FALLTHRU */ 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 3750Sstevel@tonic-gate sadp->sa_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 3760Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) == 1) 3770Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 3780Sstevel@tonic-gate else 3790Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 3800Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, size, NULL); 3810Sstevel@tonic-gate qreply(qp, mp); 3820Sstevel@tonic-gate break; 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate default: 3850Sstevel@tonic-gate ASSERT(0); 3860Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3870Sstevel@tonic-gate break; 3880Sstevel@tonic-gate } /* switch (ioc_cmd) */ 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate /* 3920Sstevel@tonic-gate * apush_iocdata() - 3930Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 3940Sstevel@tonic-gate * the autopush feature. 3950Sstevel@tonic-gate */ 3960Sstevel@tonic-gate static void 3970Sstevel@tonic-gate apush_iocdata( 3980Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 3990Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 4000Sstevel@tonic-gate { 4010Sstevel@tonic-gate int i, ret; 4020Sstevel@tonic-gate struct copyresp *csp; 4033064Sedp struct strapush *sap = NULL; 4043042Sedp struct autopush *ap, *ap_tmp; 4050Sstevel@tonic-gate struct saddev *sadp; 4060Sstevel@tonic-gate uint_t size; 4073042Sedp dev_t dev; 4083448Sdh155122 str_stack_t *ss; 4093448Sdh155122 4103448Sdh155122 sadp = (struct saddev *)qp->q_ptr; 4113448Sdh155122 ss = sadp->sa_ss; 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 4140Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 4150Sstevel@tonic-gate freemsg(mp); 4160Sstevel@tonic-gate return; 4170Sstevel@tonic-gate } 4183042Sedp if (mp->b_cont) { 4193042Sedp /* 4203064Sedp * sap needed only if mp->b_cont is set. figure out the 4213064Sedp * size of the expected sap structure and make sure 4223064Sedp * enough data was supplied. 4233042Sedp */ 4243064Sedp if (SAD_VER(csp->cp_cmd) == 1) 4253064Sedp size = STRAPUSH_V1_LEN; 4263064Sedp else 4273064Sedp size = STRAPUSH_V0_LEN; 4283064Sedp if (MBLKL(mp->b_cont) < size) { 4293064Sedp miocnak(qp, mp, 0, EINVAL); 4303042Sedp return; 4313042Sedp } 4320Sstevel@tonic-gate sap = (struct strapush *)mp->b_cont->b_rptr; 4333042Sedp dev = makedevice(sap->sap_major, sap->sap_minor); 4343042Sedp } 4350Sstevel@tonic-gate switch (SAD_CMD(csp->cp_cmd)) { 4360Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 4370Sstevel@tonic-gate 4383042Sedp /* currently we only support one SAD_SAP command */ 4393042Sedp if (((long)csp->cp_private) != GETSTRUCT) { 4400Sstevel@tonic-gate cmn_err(CE_WARN, 4410Sstevel@tonic-gate "apush_iocdata: cp_private bad in SAD_SAP: %p", 4420Sstevel@tonic-gate (void *)csp->cp_private); 4433042Sedp miocnak(qp, mp, 0, EINVAL); 4443042Sedp return; 4453042Sedp } 4463042Sedp 4473042Sedp switch (sap->sap_cmd) { 4483042Sedp default: 4493042Sedp miocnak(qp, mp, 0, EINVAL); 4503042Sedp return; 4513042Sedp case SAP_ONE: 4523042Sedp case SAP_RANGE: 4533042Sedp case SAP_ALL: 4543042Sedp /* allocate and initialize a new config */ 4553042Sedp ap = sad_ap_alloc(); 4563042Sedp ap->ap_common = sap->sap_common; 4573042Sedp if (SAD_VER(csp->cp_cmd) > 0) 4583042Sedp ap->ap_anchor = sap->sap_anchor; 4593042Sedp for (i = 0; i < MIN(sap->sap_npush, MAXAPUSH); i++) 4603042Sedp (void) strncpy(ap->ap_list[i], 4613042Sedp sap->sap_list[i], FMNAMESZ); 4623042Sedp 4633042Sedp /* sanity check the request */ 4643042Sedp if (((ret = sad_ap_verify(ap)) != 0) || 4653042Sedp ((ret = valid_major(ap->ap_major)) != 0)) { 4663448Sdh155122 sad_ap_rele(ap, ss); 4673042Sedp miocnak(qp, mp, 0, ret); 4683042Sedp return; 4693042Sedp } 4703042Sedp 4713042Sedp /* check for overlapping configs */ 4723448Sdh155122 mutex_enter(&ss->ss_sad_lock); 4733448Sdh155122 ap_tmp = sad_ap_find(&ap->ap_common, ss); 4743448Sdh155122 if (ap_tmp != NULL) { 4753042Sedp /* already configured */ 4763448Sdh155122 mutex_exit(&ss->ss_sad_lock); 4773448Sdh155122 sad_ap_rele(ap_tmp, ss); 4783448Sdh155122 sad_ap_rele(ap, ss); 4793042Sedp miocnak(qp, mp, 0, EEXIST); 4803042Sedp return; 4813042Sedp } 4823042Sedp 4833042Sedp /* add the new config to our hash */ 4843448Sdh155122 sad_ap_insert(ap, ss); 4853448Sdh155122 mutex_exit(&ss->ss_sad_lock); 4863042Sedp miocack(qp, mp, 0, 0); 4873042Sedp return; 4883042Sedp 4893042Sedp case SAP_CLEAR: 4903042Sedp /* sanity check the request */ 4913042Sedp if (ret = valid_major(sap->sap_major)) { 4923042Sedp miocnak(qp, mp, 0, ret); 4933042Sedp return; 4943042Sedp } 4953042Sedp 4963042Sedp /* search for a matching config */ 4973448Sdh155122 if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { 4983042Sedp /* no config found */ 4993042Sedp miocnak(qp, mp, 0, ENODEV); 5003042Sedp return; 5013042Sedp } 5023042Sedp 5033042Sedp /* 5043042Sedp * If we matched a SAP_RANGE config 5053042Sedp * the minor passed in must match the 5063042Sedp * beginning of the range exactly. 5073042Sedp */ 5083042Sedp if ((ap->ap_type == SAP_RANGE) && 5093042Sedp (ap->ap_minor != sap->sap_minor)) { 5103448Sdh155122 sad_ap_rele(ap, ss); 5113042Sedp miocnak(qp, mp, 0, ERANGE); 5123042Sedp return; 5133042Sedp } 5143042Sedp 5153042Sedp /* 5163042Sedp * If we matched a SAP_ALL config 5173042Sedp * the minor passed in must be 0. 5183042Sedp */ 5193042Sedp if ((ap->ap_type == SAP_ALL) && 5203042Sedp (sap->sap_minor != 0)) { 5213448Sdh155122 sad_ap_rele(ap, ss); 5223042Sedp miocnak(qp, mp, 0, EINVAL); 5233042Sedp return; 5243042Sedp } 5253042Sedp 5263042Sedp /* 5273042Sedp * make sure someone else hasn't already 5283042Sedp * removed this config from the hash. 5293042Sedp */ 5303448Sdh155122 mutex_enter(&ss->ss_sad_lock); 5313448Sdh155122 ap_tmp = sad_ap_find(&ap->ap_common, ss); 5323042Sedp if (ap_tmp != ap) { 5333448Sdh155122 mutex_exit(&ss->ss_sad_lock); 5343448Sdh155122 sad_ap_rele(ap_tmp, ss); 5353448Sdh155122 sad_ap_rele(ap, ss); 5363042Sedp miocnak(qp, mp, 0, ENODEV); 5373042Sedp return; 5383448Sdh155122 } 5393042Sedp 5403042Sedp /* remove the config from the hash and return */ 5413448Sdh155122 sad_ap_remove(ap, ss); 5423448Sdh155122 mutex_exit(&ss->ss_sad_lock); 5433042Sedp 5443042Sedp /* 5453042Sedp * Release thrice, once for sad_ap_find_by_dev(), 5463042Sedp * once for sad_ap_find(), and once to free. 5473042Sedp */ 5483448Sdh155122 sad_ap_rele(ap, ss); 5493448Sdh155122 sad_ap_rele(ap, ss); 5503448Sdh155122 sad_ap_rele(ap, ss); 5513042Sedp miocack(qp, mp, 0, 0); 5523042Sedp return; 5533042Sedp } /* switch (sap_cmd) */ 5543042Sedp /*NOTREACHED*/ 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 5570Sstevel@tonic-gate switch ((long)csp->cp_private) { 5580Sstevel@tonic-gate 5593042Sedp case GETSTRUCT: 5603042Sedp /* sanity check the request */ 5610Sstevel@tonic-gate if (ret = valid_major(sap->sap_major)) { 5620Sstevel@tonic-gate miocnak(qp, mp, 0, ret); 5633042Sedp return; 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate 5663042Sedp /* search for a matching config */ 5673448Sdh155122 if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { 5683042Sedp /* no config found */ 5693042Sedp miocnak(qp, mp, 0, ENODEV); 5703042Sedp return; 5713042Sedp } 5723042Sedp 5733042Sedp /* copy out the contents of the config */ 5740Sstevel@tonic-gate sap->sap_common = ap->ap_common; 5750Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) > 0) 5760Sstevel@tonic-gate sap->sap_anchor = ap->ap_anchor; 5770Sstevel@tonic-gate for (i = 0; i < ap->ap_npush; i++) 5780Sstevel@tonic-gate (void) strcpy(sap->sap_list[i], ap->ap_list[i]); 5790Sstevel@tonic-gate for (; i < MAXAPUSH; i++) 5800Sstevel@tonic-gate bzero(sap->sap_list[i], FMNAMESZ + 1); 5810Sstevel@tonic-gate 5823042Sedp /* release our hold on the config */ 5833448Sdh155122 sad_ap_rele(ap, ss); 5843042Sedp 5853042Sedp /* copyout the results */ 5860Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) == 1) 5870Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 5880Sstevel@tonic-gate else 5890Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate mcopyout(mp, (void *)GETRESULT, size, sadp->sa_addr, 5920Sstevel@tonic-gate NULL); 5930Sstevel@tonic-gate qreply(qp, mp); 5943042Sedp return; 5950Sstevel@tonic-gate case GETRESULT: 5960Sstevel@tonic-gate miocack(qp, mp, 0, 0); 5973042Sedp return; 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate default: 6000Sstevel@tonic-gate cmn_err(CE_WARN, 6010Sstevel@tonic-gate "apush_iocdata: cp_private bad case SAD_GAP: %p", 6020Sstevel@tonic-gate (void *)csp->cp_private); 6030Sstevel@tonic-gate freemsg(mp); 6043042Sedp return; 6050Sstevel@tonic-gate } /* switch (cp_private) */ 6063042Sedp /*NOTREACHED*/ 6070Sstevel@tonic-gate default: /* can't happen */ 6080Sstevel@tonic-gate ASSERT(0); 6090Sstevel@tonic-gate freemsg(mp); 6103042Sedp return; 6110Sstevel@tonic-gate } /* switch (cp_cmd) */ 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate /* 6150Sstevel@tonic-gate * vml_ioctl() - 6160Sstevel@tonic-gate * Handle the M_IOCTL message associated with a request 6170Sstevel@tonic-gate * to validate a module list. 6180Sstevel@tonic-gate */ 6190Sstevel@tonic-gate static void 6200Sstevel@tonic-gate vml_ioctl( 6210Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 6220Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 6230Sstevel@tonic-gate { 6240Sstevel@tonic-gate struct iocblk *iocp; 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 6270Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 6280Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 6290Sstevel@tonic-gate return; 6300Sstevel@tonic-gate } 6313324Sethindra ASSERT(SAD_CMD(iocp->ioc_cmd) == SAD_VML); 6320Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, 6330Sstevel@tonic-gate SIZEOF_STRUCT(str_list, iocp->ioc_flag), NULL); 6340Sstevel@tonic-gate qreply(qp, mp); 6350Sstevel@tonic-gate } 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate /* 6380Sstevel@tonic-gate * vml_iocdata() - 6390Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 6400Sstevel@tonic-gate * a request to validate a module list. 6410Sstevel@tonic-gate */ 6420Sstevel@tonic-gate static void 6430Sstevel@tonic-gate vml_iocdata( 6440Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 6450Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 6460Sstevel@tonic-gate { 6470Sstevel@tonic-gate long i; 6480Sstevel@tonic-gate int nmods; 6490Sstevel@tonic-gate struct copyresp *csp; 6500Sstevel@tonic-gate struct str_mlist *lp; 6510Sstevel@tonic-gate STRUCT_HANDLE(str_list, slp); 6520Sstevel@tonic-gate struct saddev *sadp; 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 6550Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 6560Sstevel@tonic-gate freemsg(mp); 6570Sstevel@tonic-gate return; 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate 6603324Sethindra ASSERT(SAD_CMD(csp->cp_cmd) == SAD_VML); 6610Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 6620Sstevel@tonic-gate switch ((long)csp->cp_private) { 6630Sstevel@tonic-gate case GETSTRUCT: 6640Sstevel@tonic-gate STRUCT_SET_HANDLE(slp, csp->cp_flag, 6650Sstevel@tonic-gate (struct str_list *)mp->b_cont->b_rptr); 6660Sstevel@tonic-gate nmods = STRUCT_FGET(slp, sl_nmods); 6670Sstevel@tonic-gate if (nmods <= 0) { 6680Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 6690Sstevel@tonic-gate break; 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate sadp->sa_addr = (caddr_t)(uintptr_t)nmods; 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate mcopyin(mp, (void *)GETLIST, nmods * sizeof (struct str_mlist), 6740Sstevel@tonic-gate STRUCT_FGETP(slp, sl_modlist)); 6750Sstevel@tonic-gate qreply(qp, mp); 6760Sstevel@tonic-gate break; 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate case GETLIST: 6790Sstevel@tonic-gate lp = (struct str_mlist *)mp->b_cont->b_rptr; 6800Sstevel@tonic-gate for (i = 0; i < (long)sadp->sa_addr; i++, lp++) { 6810Sstevel@tonic-gate lp->l_name[FMNAMESZ] = '\0'; 6820Sstevel@tonic-gate if (fmodsw_find(lp->l_name, FMODSW_LOAD) == NULL) { 6830Sstevel@tonic-gate miocack(qp, mp, 0, 1); 6840Sstevel@tonic-gate return; 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate } 6870Sstevel@tonic-gate miocack(qp, mp, 0, 0); 6880Sstevel@tonic-gate break; 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate default: 6910Sstevel@tonic-gate cmn_err(CE_WARN, "vml_iocdata: invalid cp_private value: %p", 6920Sstevel@tonic-gate (void *)csp->cp_private); 6930Sstevel@tonic-gate freemsg(mp); 6940Sstevel@tonic-gate break; 6950Sstevel@tonic-gate } /* switch (cp_private) */ 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate /* 6990Sstevel@tonic-gate * Validate a major number and also verify if 7000Sstevel@tonic-gate * it is a STREAMS device. 7010Sstevel@tonic-gate * Return values: 0 if a valid STREAMS dev 7020Sstevel@tonic-gate * error code otherwise 7030Sstevel@tonic-gate */ 7040Sstevel@tonic-gate static int 7050Sstevel@tonic-gate valid_major(major_t major) 7060Sstevel@tonic-gate { 7070Sstevel@tonic-gate int ret = 0; 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate if (etoimajor(major) == -1) 7100Sstevel@tonic-gate return (EINVAL); 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate /* 7130Sstevel@tonic-gate * attempt to load the driver 'major' and verify that 7140Sstevel@tonic-gate * it is a STREAMS driver. 7150Sstevel@tonic-gate */ 7160Sstevel@tonic-gate if (ddi_hold_driver(major) == NULL) 7170Sstevel@tonic-gate return (EINVAL); 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate if (!STREAMSTAB(major)) 7200Sstevel@tonic-gate ret = ENOSTR; 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate ddi_rele_driver(major); 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate return (ret); 7250Sstevel@tonic-gate } 726