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 /* 22*3448Sdh155122 * 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> 550Sstevel@tonic-gate #include <sys/priv_names.h> 563042Sedp #include <sys/sysmacros.h> 57*3448Sdh155122 #include <sys/zone.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, 893042Sedp nodev, nodev, sad_info, D_MTPERQ | D_MP, &sadinfo); 900Sstevel@tonic-gate 910Sstevel@tonic-gate /* 920Sstevel@tonic-gate * Module linkage information for the kernel. 930Sstevel@tonic-gate */ 940Sstevel@tonic-gate 950Sstevel@tonic-gate static struct modldrv modldrv = { 960Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 970Sstevel@tonic-gate "STREAMS Administrative Driver 'sad' %I%", 980Sstevel@tonic-gate &sad_ops, /* driver ops */ 990Sstevel@tonic-gate }; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate static struct modlinkage modlinkage = { 1020Sstevel@tonic-gate MODREV_1, &modldrv, NULL 1030Sstevel@tonic-gate }; 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate int 1060Sstevel@tonic-gate _init(void) 1070Sstevel@tonic-gate { 1080Sstevel@tonic-gate return (mod_install(&modlinkage)); 1090Sstevel@tonic-gate } 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate int 1120Sstevel@tonic-gate _fini(void) 1130Sstevel@tonic-gate { 1140Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate int 1180Sstevel@tonic-gate _info(struct modinfo *modinfop) 1190Sstevel@tonic-gate { 1200Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1210Sstevel@tonic-gate } 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate static int 1240Sstevel@tonic-gate sad_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 1250Sstevel@tonic-gate { 1263042Sedp int instance = ddi_get_instance(devi); 1273042Sedp 1280Sstevel@tonic-gate if (cmd != DDI_ATTACH) 1290Sstevel@tonic-gate return (DDI_FAILURE); 1300Sstevel@tonic-gate 1313042Sedp ASSERT(instance == 0); 1323042Sedp if (instance != 0) 1333042Sedp return (DDI_FAILURE); 1343042Sedp 1350Sstevel@tonic-gate if (ddi_create_minor_node(devi, "user", S_IFCHR, 1360Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 1370Sstevel@tonic-gate return (DDI_FAILURE); 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate if (ddi_create_priv_minor_node(devi, "admin", S_IFCHR, 1400Sstevel@tonic-gate 1, DDI_PSEUDO, PRIVONLY_DEV, PRIV_SYS_CONFIG, 1410Sstevel@tonic-gate PRIV_SYS_CONFIG, 0666) == 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; 190*3448Sdh155122 netstack_t *ns; 191*3448Sdh155122 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*3448Sdh155122 ns = netstack_find_by_cred(credp); 197*3448Sdh155122 ASSERT(ns != NULL); 198*3448Sdh155122 ss = ns->netstack_str; 199*3448Sdh155122 ASSERT(ss != NULL); 200*3448Sdh155122 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces. 2030Sstevel@tonic-gate */ 204*3448Sdh155122 for (i = 0; i < ss->ss_sadcnt; i++) 205*3448Sdh155122 if (ss->ss_saddev[i].sa_qp == NULL) 2060Sstevel@tonic-gate break; 207*3448Sdh155122 if (i >= ss->ss_sadcnt) { /* no such device */ 208*3448Sdh155122 netstack_rele(ss->ss_netstack); 2090Sstevel@tonic-gate return (ENXIO); 210*3448Sdh155122 } 2110Sstevel@tonic-gate switch (getminor(*devp)) { 2120Sstevel@tonic-gate case USRMIN: /* mere mortal */ 213*3448Sdh155122 ss->ss_saddev[i].sa_flags = 0; 2140Sstevel@tonic-gate break; 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate case ADMMIN: /* privileged user */ 217*3448Sdh155122 ss->ss_saddev[i].sa_flags = SADPRIV; 2180Sstevel@tonic-gate break; 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate default: 221*3448Sdh155122 netstack_rele(ss->ss_netstack); 2220Sstevel@tonic-gate return (EINVAL); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate 225*3448Sdh155122 ss->ss_saddev[i].sa_qp = qp; 226*3448Sdh155122 ss->ss_saddev[i].sa_ss = ss; 227*3448Sdh155122 qp->q_ptr = (caddr_t)&ss->ss_saddev[i]; 228*3448Sdh155122 WR(qp)->q_ptr = (caddr_t)&ss->ss_saddev[i]; 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* 2310Sstevel@tonic-gate * NOTE: should the ADMMIN or USRMIN minors change 2320Sstevel@tonic-gate * then so should the offset of 2 below 2330Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces and 2340Sstevel@tonic-gate * therefore their minor numbers (0 and 1) are reserved. 2350Sstevel@tonic-gate */ 2360Sstevel@tonic-gate *devp = makedevice(getemajor(*devp), i + 2); 2370Sstevel@tonic-gate qprocson(qp); 2380Sstevel@tonic-gate return (0); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate /* 2420Sstevel@tonic-gate * sadclose() - 2430Sstevel@tonic-gate * Clean up the data structures. 2440Sstevel@tonic-gate */ 2450Sstevel@tonic-gate /* ARGSUSED */ 2460Sstevel@tonic-gate static int 2470Sstevel@tonic-gate sadclose( 2480Sstevel@tonic-gate queue_t *qp, /* pointer to read queue */ 2490Sstevel@tonic-gate int flag, /* file open flags */ 2500Sstevel@tonic-gate cred_t *credp) /* user credentials */ 2510Sstevel@tonic-gate { 2520Sstevel@tonic-gate struct saddev *sadp; 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate qprocsoff(qp); 2550Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 2560Sstevel@tonic-gate sadp->sa_qp = NULL; 2570Sstevel@tonic-gate sadp->sa_addr = NULL; 258*3448Sdh155122 netstack_rele(sadp->sa_ss->ss_netstack); 259*3448Sdh155122 sadp->sa_ss = NULL; 2600Sstevel@tonic-gate qp->q_ptr = NULL; 2610Sstevel@tonic-gate WR(qp)->q_ptr = NULL; 2620Sstevel@tonic-gate return (0); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate /* 2660Sstevel@tonic-gate * sadwput() - 2670Sstevel@tonic-gate * Write side put procedure. 2680Sstevel@tonic-gate */ 2690Sstevel@tonic-gate static int 2700Sstevel@tonic-gate sadwput( 2710Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 2720Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 2730Sstevel@tonic-gate { 2740Sstevel@tonic-gate struct iocblk *iocp; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate switch (mp->b_datap->db_type) { 2770Sstevel@tonic-gate case M_FLUSH: 2780Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 2790Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 2800Sstevel@tonic-gate qreply(qp, mp); 2810Sstevel@tonic-gate } else 2820Sstevel@tonic-gate freemsg(mp); 2830Sstevel@tonic-gate break; 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate case M_IOCTL: 2860Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 2870Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 2880Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 2890Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 2900Sstevel@tonic-gate apush_ioctl(qp, mp); 2910Sstevel@tonic-gate break; 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate case SAD_VML: 2940Sstevel@tonic-gate vml_ioctl(qp, mp); 2950Sstevel@tonic-gate break; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate default: 2980Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 2990Sstevel@tonic-gate break; 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate break; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate case M_IOCDATA: 3040Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3050Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 3060Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 3070Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 3080Sstevel@tonic-gate apush_iocdata(qp, mp); 3090Sstevel@tonic-gate break; 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate case SAD_VML: 3120Sstevel@tonic-gate vml_iocdata(qp, mp); 3130Sstevel@tonic-gate break; 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate default: 3160Sstevel@tonic-gate cmn_err(CE_WARN, 3170Sstevel@tonic-gate "sadwput: invalid ioc_cmd in case M_IOCDATA: %d", 3180Sstevel@tonic-gate iocp->ioc_cmd); 3190Sstevel@tonic-gate freemsg(mp); 3200Sstevel@tonic-gate break; 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate break; 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate default: 3250Sstevel@tonic-gate freemsg(mp); 3260Sstevel@tonic-gate break; 3270Sstevel@tonic-gate } /* switch (db_type) */ 3280Sstevel@tonic-gate return (0); 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate /* 3320Sstevel@tonic-gate * apush_ioctl() - 3330Sstevel@tonic-gate * Handle the M_IOCTL messages associated with 3340Sstevel@tonic-gate * the autopush feature. 3350Sstevel@tonic-gate */ 3360Sstevel@tonic-gate static void 3370Sstevel@tonic-gate apush_ioctl( 3380Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 3390Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 3400Sstevel@tonic-gate { 3410Sstevel@tonic-gate struct iocblk *iocp; 3420Sstevel@tonic-gate struct saddev *sadp; 3430Sstevel@tonic-gate uint_t size; 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3460Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 3470Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3480Sstevel@tonic-gate return; 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) > AP_VERSION) { 3510Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3520Sstevel@tonic-gate return; 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 3560Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 3570Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 3580Sstevel@tonic-gate if (!(sadp->sa_flags & SADPRIV)) { 3590Sstevel@tonic-gate miocnak(qp, mp, 0, EPERM); 3600Sstevel@tonic-gate break; 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate /* FALLTHRU */ 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 3650Sstevel@tonic-gate sadp->sa_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 3660Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) == 1) 3670Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 3680Sstevel@tonic-gate else 3690Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 3700Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, size, NULL); 3710Sstevel@tonic-gate qreply(qp, mp); 3720Sstevel@tonic-gate break; 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate default: 3750Sstevel@tonic-gate ASSERT(0); 3760Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3770Sstevel@tonic-gate break; 3780Sstevel@tonic-gate } /* switch (ioc_cmd) */ 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate /* 3820Sstevel@tonic-gate * apush_iocdata() - 3830Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 3840Sstevel@tonic-gate * the autopush feature. 3850Sstevel@tonic-gate */ 3860Sstevel@tonic-gate static void 3870Sstevel@tonic-gate apush_iocdata( 3880Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 3890Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 3900Sstevel@tonic-gate { 3910Sstevel@tonic-gate int i, ret; 3920Sstevel@tonic-gate struct copyresp *csp; 3933064Sedp struct strapush *sap = NULL; 3943042Sedp struct autopush *ap, *ap_tmp; 3950Sstevel@tonic-gate struct saddev *sadp; 3960Sstevel@tonic-gate uint_t size; 3973042Sedp dev_t dev; 398*3448Sdh155122 str_stack_t *ss; 399*3448Sdh155122 400*3448Sdh155122 sadp = (struct saddev *)qp->q_ptr; 401*3448Sdh155122 ss = sadp->sa_ss; 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 4040Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 4050Sstevel@tonic-gate freemsg(mp); 4060Sstevel@tonic-gate return; 4070Sstevel@tonic-gate } 4083042Sedp if (mp->b_cont) { 4093042Sedp /* 4103064Sedp * sap needed only if mp->b_cont is set. figure out the 4113064Sedp * size of the expected sap structure and make sure 4123064Sedp * enough data was supplied. 4133042Sedp */ 4143064Sedp if (SAD_VER(csp->cp_cmd) == 1) 4153064Sedp size = STRAPUSH_V1_LEN; 4163064Sedp else 4173064Sedp size = STRAPUSH_V0_LEN; 4183064Sedp if (MBLKL(mp->b_cont) < size) { 4193064Sedp miocnak(qp, mp, 0, EINVAL); 4203042Sedp return; 4213042Sedp } 4220Sstevel@tonic-gate sap = (struct strapush *)mp->b_cont->b_rptr; 4233042Sedp dev = makedevice(sap->sap_major, sap->sap_minor); 4243042Sedp } 4250Sstevel@tonic-gate switch (SAD_CMD(csp->cp_cmd)) { 4260Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 4270Sstevel@tonic-gate 4283042Sedp /* currently we only support one SAD_SAP command */ 4293042Sedp if (((long)csp->cp_private) != GETSTRUCT) { 4300Sstevel@tonic-gate cmn_err(CE_WARN, 4310Sstevel@tonic-gate "apush_iocdata: cp_private bad in SAD_SAP: %p", 4320Sstevel@tonic-gate (void *)csp->cp_private); 4333042Sedp miocnak(qp, mp, 0, EINVAL); 4343042Sedp return; 4353042Sedp } 4363042Sedp 4373042Sedp switch (sap->sap_cmd) { 4383042Sedp default: 4393042Sedp miocnak(qp, mp, 0, EINVAL); 4403042Sedp return; 4413042Sedp case SAP_ONE: 4423042Sedp case SAP_RANGE: 4433042Sedp case SAP_ALL: 4443042Sedp /* allocate and initialize a new config */ 4453042Sedp ap = sad_ap_alloc(); 4463042Sedp ap->ap_common = sap->sap_common; 4473042Sedp if (SAD_VER(csp->cp_cmd) > 0) 4483042Sedp ap->ap_anchor = sap->sap_anchor; 4493042Sedp for (i = 0; i < MIN(sap->sap_npush, MAXAPUSH); i++) 4503042Sedp (void) strncpy(ap->ap_list[i], 4513042Sedp sap->sap_list[i], FMNAMESZ); 4523042Sedp 4533042Sedp /* sanity check the request */ 4543042Sedp if (((ret = sad_ap_verify(ap)) != 0) || 4553042Sedp ((ret = valid_major(ap->ap_major)) != 0)) { 456*3448Sdh155122 sad_ap_rele(ap, ss); 4573042Sedp miocnak(qp, mp, 0, ret); 4583042Sedp return; 4593042Sedp } 4603042Sedp 4613042Sedp /* check for overlapping configs */ 462*3448Sdh155122 mutex_enter(&ss->ss_sad_lock); 463*3448Sdh155122 ap_tmp = sad_ap_find(&ap->ap_common, ss); 464*3448Sdh155122 if (ap_tmp != NULL) { 4653042Sedp /* already configured */ 466*3448Sdh155122 mutex_exit(&ss->ss_sad_lock); 467*3448Sdh155122 sad_ap_rele(ap_tmp, ss); 468*3448Sdh155122 sad_ap_rele(ap, ss); 4693042Sedp miocnak(qp, mp, 0, EEXIST); 4703042Sedp return; 4713042Sedp } 4723042Sedp 4733042Sedp /* add the new config to our hash */ 474*3448Sdh155122 sad_ap_insert(ap, ss); 475*3448Sdh155122 mutex_exit(&ss->ss_sad_lock); 4763042Sedp miocack(qp, mp, 0, 0); 4773042Sedp return; 4783042Sedp 4793042Sedp case SAP_CLEAR: 4803042Sedp /* sanity check the request */ 4813042Sedp if (ret = valid_major(sap->sap_major)) { 4823042Sedp miocnak(qp, mp, 0, ret); 4833042Sedp return; 4843042Sedp } 4853042Sedp 4863042Sedp /* search for a matching config */ 487*3448Sdh155122 if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { 4883042Sedp /* no config found */ 4893042Sedp miocnak(qp, mp, 0, ENODEV); 4903042Sedp return; 4913042Sedp } 4923042Sedp 4933042Sedp /* 4943042Sedp * If we matched a SAP_RANGE config 4953042Sedp * the minor passed in must match the 4963042Sedp * beginning of the range exactly. 4973042Sedp */ 4983042Sedp if ((ap->ap_type == SAP_RANGE) && 4993042Sedp (ap->ap_minor != sap->sap_minor)) { 500*3448Sdh155122 sad_ap_rele(ap, ss); 5013042Sedp miocnak(qp, mp, 0, ERANGE); 5023042Sedp return; 5033042Sedp } 5043042Sedp 5053042Sedp /* 5063042Sedp * If we matched a SAP_ALL config 5073042Sedp * the minor passed in must be 0. 5083042Sedp */ 5093042Sedp if ((ap->ap_type == SAP_ALL) && 5103042Sedp (sap->sap_minor != 0)) { 511*3448Sdh155122 sad_ap_rele(ap, ss); 5123042Sedp miocnak(qp, mp, 0, EINVAL); 5133042Sedp return; 5143042Sedp } 5153042Sedp 5163042Sedp /* 5173042Sedp * make sure someone else hasn't already 5183042Sedp * removed this config from the hash. 5193042Sedp */ 520*3448Sdh155122 mutex_enter(&ss->ss_sad_lock); 521*3448Sdh155122 ap_tmp = sad_ap_find(&ap->ap_common, ss); 5223042Sedp if (ap_tmp != ap) { 523*3448Sdh155122 mutex_exit(&ss->ss_sad_lock); 524*3448Sdh155122 sad_ap_rele(ap_tmp, ss); 525*3448Sdh155122 sad_ap_rele(ap, ss); 5263042Sedp miocnak(qp, mp, 0, ENODEV); 5273042Sedp return; 528*3448Sdh155122 } 5293042Sedp 5303042Sedp /* remove the config from the hash and return */ 531*3448Sdh155122 sad_ap_remove(ap, ss); 532*3448Sdh155122 mutex_exit(&ss->ss_sad_lock); 5333042Sedp 5343042Sedp /* 5353042Sedp * Release thrice, once for sad_ap_find_by_dev(), 5363042Sedp * once for sad_ap_find(), and once to free. 5373042Sedp */ 538*3448Sdh155122 sad_ap_rele(ap, ss); 539*3448Sdh155122 sad_ap_rele(ap, ss); 540*3448Sdh155122 sad_ap_rele(ap, ss); 5413042Sedp miocack(qp, mp, 0, 0); 5423042Sedp return; 5433042Sedp } /* switch (sap_cmd) */ 5443042Sedp /*NOTREACHED*/ 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 5470Sstevel@tonic-gate switch ((long)csp->cp_private) { 5480Sstevel@tonic-gate 5493042Sedp case GETSTRUCT: 5503042Sedp /* sanity check the request */ 5510Sstevel@tonic-gate if (ret = valid_major(sap->sap_major)) { 5520Sstevel@tonic-gate miocnak(qp, mp, 0, ret); 5533042Sedp return; 5540Sstevel@tonic-gate } 5550Sstevel@tonic-gate 5563042Sedp /* search for a matching config */ 557*3448Sdh155122 if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { 5583042Sedp /* no config found */ 5593042Sedp miocnak(qp, mp, 0, ENODEV); 5603042Sedp return; 5613042Sedp } 5623042Sedp 5633042Sedp /* copy out the contents of the config */ 5640Sstevel@tonic-gate sap->sap_common = ap->ap_common; 5650Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) > 0) 5660Sstevel@tonic-gate sap->sap_anchor = ap->ap_anchor; 5670Sstevel@tonic-gate for (i = 0; i < ap->ap_npush; i++) 5680Sstevel@tonic-gate (void) strcpy(sap->sap_list[i], ap->ap_list[i]); 5690Sstevel@tonic-gate for (; i < MAXAPUSH; i++) 5700Sstevel@tonic-gate bzero(sap->sap_list[i], FMNAMESZ + 1); 571*3448Sdh155122 mutex_exit(&ss->ss_sad_lock); 5720Sstevel@tonic-gate 5733042Sedp /* release our hold on the config */ 574*3448Sdh155122 sad_ap_rele(ap, ss); 5753042Sedp 5763042Sedp /* copyout the results */ 5770Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) == 1) 5780Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 5790Sstevel@tonic-gate else 5800Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate mcopyout(mp, (void *)GETRESULT, size, sadp->sa_addr, 5830Sstevel@tonic-gate NULL); 5840Sstevel@tonic-gate qreply(qp, mp); 5853042Sedp return; 5860Sstevel@tonic-gate case GETRESULT: 5870Sstevel@tonic-gate miocack(qp, mp, 0, 0); 5883042Sedp return; 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate default: 5910Sstevel@tonic-gate cmn_err(CE_WARN, 5920Sstevel@tonic-gate "apush_iocdata: cp_private bad case SAD_GAP: %p", 5930Sstevel@tonic-gate (void *)csp->cp_private); 5940Sstevel@tonic-gate freemsg(mp); 5953042Sedp return; 5960Sstevel@tonic-gate } /* switch (cp_private) */ 5973042Sedp /*NOTREACHED*/ 5980Sstevel@tonic-gate default: /* can't happen */ 5990Sstevel@tonic-gate ASSERT(0); 6000Sstevel@tonic-gate freemsg(mp); 6013042Sedp return; 6020Sstevel@tonic-gate } /* switch (cp_cmd) */ 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate /* 6060Sstevel@tonic-gate * vml_ioctl() - 6070Sstevel@tonic-gate * Handle the M_IOCTL message associated with a request 6080Sstevel@tonic-gate * to validate a module list. 6090Sstevel@tonic-gate */ 6100Sstevel@tonic-gate static void 6110Sstevel@tonic-gate vml_ioctl( 6120Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 6130Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 6140Sstevel@tonic-gate { 6150Sstevel@tonic-gate struct iocblk *iocp; 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 6180Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 6190Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 6200Sstevel@tonic-gate return; 6210Sstevel@tonic-gate } 6223324Sethindra ASSERT(SAD_CMD(iocp->ioc_cmd) == SAD_VML); 6230Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, 6240Sstevel@tonic-gate SIZEOF_STRUCT(str_list, iocp->ioc_flag), NULL); 6250Sstevel@tonic-gate qreply(qp, mp); 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate /* 6290Sstevel@tonic-gate * vml_iocdata() - 6300Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 6310Sstevel@tonic-gate * a request to validate a module list. 6320Sstevel@tonic-gate */ 6330Sstevel@tonic-gate static void 6340Sstevel@tonic-gate vml_iocdata( 6350Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 6360Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 6370Sstevel@tonic-gate { 6380Sstevel@tonic-gate long i; 6390Sstevel@tonic-gate int nmods; 6400Sstevel@tonic-gate struct copyresp *csp; 6410Sstevel@tonic-gate struct str_mlist *lp; 6420Sstevel@tonic-gate STRUCT_HANDLE(str_list, slp); 6430Sstevel@tonic-gate struct saddev *sadp; 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 6460Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 6470Sstevel@tonic-gate freemsg(mp); 6480Sstevel@tonic-gate return; 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate 6513324Sethindra ASSERT(SAD_CMD(csp->cp_cmd) == SAD_VML); 6520Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 6530Sstevel@tonic-gate switch ((long)csp->cp_private) { 6540Sstevel@tonic-gate case GETSTRUCT: 6550Sstevel@tonic-gate STRUCT_SET_HANDLE(slp, csp->cp_flag, 6560Sstevel@tonic-gate (struct str_list *)mp->b_cont->b_rptr); 6570Sstevel@tonic-gate nmods = STRUCT_FGET(slp, sl_nmods); 6580Sstevel@tonic-gate if (nmods <= 0) { 6590Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 6600Sstevel@tonic-gate break; 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate sadp->sa_addr = (caddr_t)(uintptr_t)nmods; 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate mcopyin(mp, (void *)GETLIST, nmods * sizeof (struct str_mlist), 6650Sstevel@tonic-gate STRUCT_FGETP(slp, sl_modlist)); 6660Sstevel@tonic-gate qreply(qp, mp); 6670Sstevel@tonic-gate break; 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate case GETLIST: 6700Sstevel@tonic-gate lp = (struct str_mlist *)mp->b_cont->b_rptr; 6710Sstevel@tonic-gate for (i = 0; i < (long)sadp->sa_addr; i++, lp++) { 6720Sstevel@tonic-gate lp->l_name[FMNAMESZ] = '\0'; 6730Sstevel@tonic-gate if (fmodsw_find(lp->l_name, FMODSW_LOAD) == NULL) { 6740Sstevel@tonic-gate miocack(qp, mp, 0, 1); 6750Sstevel@tonic-gate return; 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate miocack(qp, mp, 0, 0); 6790Sstevel@tonic-gate break; 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate default: 6820Sstevel@tonic-gate cmn_err(CE_WARN, "vml_iocdata: invalid cp_private value: %p", 6830Sstevel@tonic-gate (void *)csp->cp_private); 6840Sstevel@tonic-gate freemsg(mp); 6850Sstevel@tonic-gate break; 6860Sstevel@tonic-gate } /* switch (cp_private) */ 6870Sstevel@tonic-gate } 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate /* 6900Sstevel@tonic-gate * Validate a major number and also verify if 6910Sstevel@tonic-gate * it is a STREAMS device. 6920Sstevel@tonic-gate * Return values: 0 if a valid STREAMS dev 6930Sstevel@tonic-gate * error code otherwise 6940Sstevel@tonic-gate */ 6950Sstevel@tonic-gate static int 6960Sstevel@tonic-gate valid_major(major_t major) 6970Sstevel@tonic-gate { 6980Sstevel@tonic-gate int ret = 0; 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate if (etoimajor(major) == -1) 7010Sstevel@tonic-gate return (EINVAL); 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate /* 7040Sstevel@tonic-gate * attempt to load the driver 'major' and verify that 7050Sstevel@tonic-gate * it is a STREAMS driver. 7060Sstevel@tonic-gate */ 7070Sstevel@tonic-gate if (ddi_hold_driver(major) == NULL) 7080Sstevel@tonic-gate return (EINVAL); 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate if (!STREAMSTAB(major)) 7110Sstevel@tonic-gate ret = ENOSTR; 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate ddi_rele_driver(major); 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate return (ret); 7160Sstevel@tonic-gate } 717