1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 30*0Sstevel@tonic-gate /* All Rights Reserved */ 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate /* 34*0Sstevel@tonic-gate * STREAMS Administrative Driver 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * Currently only handles autopush and module name verification. 37*0Sstevel@tonic-gate */ 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #include <sys/types.h> 40*0Sstevel@tonic-gate #include <sys/param.h> 41*0Sstevel@tonic-gate #include <sys/errno.h> 42*0Sstevel@tonic-gate #include <sys/stream.h> 43*0Sstevel@tonic-gate #include <sys/stropts.h> 44*0Sstevel@tonic-gate #include <sys/strsubr.h> 45*0Sstevel@tonic-gate #include <sys/strsun.h> 46*0Sstevel@tonic-gate #include <sys/conf.h> 47*0Sstevel@tonic-gate #include <sys/sad.h> 48*0Sstevel@tonic-gate #include <sys/cred.h> 49*0Sstevel@tonic-gate #include <sys/debug.h> 50*0Sstevel@tonic-gate #include <sys/ddi.h> 51*0Sstevel@tonic-gate #include <sys/sunddi.h> 52*0Sstevel@tonic-gate #include <sys/stat.h> 53*0Sstevel@tonic-gate #include <sys/cmn_err.h> 54*0Sstevel@tonic-gate #include <sys/systm.h> 55*0Sstevel@tonic-gate #include <sys/modctl.h> 56*0Sstevel@tonic-gate #include <sys/priv_names.h> 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate static int sadopen(queue_t *, dev_t *, int, int, cred_t *); 59*0Sstevel@tonic-gate static int sadclose(queue_t *, int, cred_t *); 60*0Sstevel@tonic-gate static int sadwput(queue_t *qp, mblk_t *mp); 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate static int sad_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 63*0Sstevel@tonic-gate static int sad_attach(dev_info_t *, ddi_attach_cmd_t); 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate static struct autopush *ap_alloc(), *ap_hfind(); 66*0Sstevel@tonic-gate static void ap_hadd(), ap_hrmv(); 67*0Sstevel@tonic-gate static void apush_ioctl(), apush_iocdata(); 68*0Sstevel@tonic-gate static void vml_ioctl(), vml_iocdata(); 69*0Sstevel@tonic-gate static int valid_major(major_t); 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate extern kmutex_t sad_lock; 72*0Sstevel@tonic-gate static dev_info_t *sad_dip; /* private copy of devinfo pointer */ 73*0Sstevel@tonic-gate static struct autopush *strpfreep; /* autopush freelist */ 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate static struct module_info sad_minfo = { 76*0Sstevel@tonic-gate 0x7361, "sad", 0, INFPSZ, 0, 0 77*0Sstevel@tonic-gate }; 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate static struct qinit sad_rinit = { 80*0Sstevel@tonic-gate NULL, NULL, sadopen, sadclose, NULL, &sad_minfo, NULL 81*0Sstevel@tonic-gate }; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate static struct qinit sad_winit = { 84*0Sstevel@tonic-gate sadwput, NULL, NULL, NULL, NULL, &sad_minfo, NULL 85*0Sstevel@tonic-gate }; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate struct streamtab sadinfo = { 88*0Sstevel@tonic-gate &sad_rinit, &sad_winit, NULL, NULL 89*0Sstevel@tonic-gate }; 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(sad_ops, nulldev, nulldev, sad_attach, 92*0Sstevel@tonic-gate nodev, nodev, sad_info, D_NEW | D_MTPERQ | D_MP, &sadinfo); 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* 95*0Sstevel@tonic-gate * Module linkage information for the kernel. 96*0Sstevel@tonic-gate */ 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate static struct modldrv modldrv = { 99*0Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 100*0Sstevel@tonic-gate "STREAMS Administrative Driver 'sad' %I%", 101*0Sstevel@tonic-gate &sad_ops, /* driver ops */ 102*0Sstevel@tonic-gate }; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 105*0Sstevel@tonic-gate MODREV_1, &modldrv, NULL 106*0Sstevel@tonic-gate }; 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate int 109*0Sstevel@tonic-gate _init(void) 110*0Sstevel@tonic-gate { 111*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate int 115*0Sstevel@tonic-gate _fini(void) 116*0Sstevel@tonic-gate { 117*0Sstevel@tonic-gate return (mod_remove(&modlinkage)); 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate int 121*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 122*0Sstevel@tonic-gate { 123*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate static int 127*0Sstevel@tonic-gate sad_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 128*0Sstevel@tonic-gate { 129*0Sstevel@tonic-gate if (cmd != DDI_ATTACH) 130*0Sstevel@tonic-gate return (DDI_FAILURE); 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, "user", S_IFCHR, 133*0Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 134*0Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 135*0Sstevel@tonic-gate return (DDI_FAILURE); 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate if (ddi_create_priv_minor_node(devi, "admin", S_IFCHR, 138*0Sstevel@tonic-gate 1, DDI_PSEUDO, PRIVONLY_DEV, PRIV_SYS_CONFIG, 139*0Sstevel@tonic-gate PRIV_SYS_CONFIG, 0666) == DDI_FAILURE) { 140*0Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 141*0Sstevel@tonic-gate return (DDI_FAILURE); 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate sad_dip = devi; 144*0Sstevel@tonic-gate return (DDI_SUCCESS); 145*0Sstevel@tonic-gate } 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate /* ARGSUSED */ 148*0Sstevel@tonic-gate static int 149*0Sstevel@tonic-gate sad_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 150*0Sstevel@tonic-gate { 151*0Sstevel@tonic-gate int error; 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate switch (infocmd) { 154*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 155*0Sstevel@tonic-gate if (sad_dip == NULL) { 156*0Sstevel@tonic-gate error = DDI_FAILURE; 157*0Sstevel@tonic-gate } else { 158*0Sstevel@tonic-gate *result = sad_dip; 159*0Sstevel@tonic-gate error = DDI_SUCCESS; 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate break; 162*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 163*0Sstevel@tonic-gate *result = (void *)0; 164*0Sstevel@tonic-gate error = DDI_SUCCESS; 165*0Sstevel@tonic-gate break; 166*0Sstevel@tonic-gate default: 167*0Sstevel@tonic-gate error = DDI_FAILURE; 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate return (error); 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate /* 174*0Sstevel@tonic-gate * sadinit() - 175*0Sstevel@tonic-gate * Initialize autopush freelist. 176*0Sstevel@tonic-gate */ 177*0Sstevel@tonic-gate void 178*0Sstevel@tonic-gate sadinit() 179*0Sstevel@tonic-gate { 180*0Sstevel@tonic-gate struct autopush *ap; 181*0Sstevel@tonic-gate int i; 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate /* 184*0Sstevel@tonic-gate * build the autopush freelist. 185*0Sstevel@tonic-gate */ 186*0Sstevel@tonic-gate strpfreep = autopush; 187*0Sstevel@tonic-gate ap = autopush; 188*0Sstevel@tonic-gate for (i = 1; i < nautopush; i++) { 189*0Sstevel@tonic-gate ap->ap_nextp = &autopush[i]; 190*0Sstevel@tonic-gate ap->ap_flags = APFREE; 191*0Sstevel@tonic-gate ap = ap->ap_nextp; 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate ap->ap_nextp = NULL; 194*0Sstevel@tonic-gate ap->ap_flags = APFREE; 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* 198*0Sstevel@tonic-gate * sadopen() - 199*0Sstevel@tonic-gate * Allocate a sad device. Only one 200*0Sstevel@tonic-gate * open at a time allowed per device. 201*0Sstevel@tonic-gate */ 202*0Sstevel@tonic-gate /* ARGSUSED */ 203*0Sstevel@tonic-gate static int 204*0Sstevel@tonic-gate sadopen( 205*0Sstevel@tonic-gate queue_t *qp, /* pointer to read queue */ 206*0Sstevel@tonic-gate dev_t *devp, /* major/minor device of stream */ 207*0Sstevel@tonic-gate int flag, /* file open flags */ 208*0Sstevel@tonic-gate int sflag, /* stream open flags */ 209*0Sstevel@tonic-gate cred_t *credp) /* user credentials */ 210*0Sstevel@tonic-gate { 211*0Sstevel@tonic-gate int i; 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate if (sflag) /* no longer called from clone driver */ 214*0Sstevel@tonic-gate return (EINVAL); 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate /* 217*0Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces. 218*0Sstevel@tonic-gate */ 219*0Sstevel@tonic-gate for (i = 0; i < sadcnt; i++) 220*0Sstevel@tonic-gate if (saddev[i].sa_qp == NULL) 221*0Sstevel@tonic-gate break; 222*0Sstevel@tonic-gate if (i >= sadcnt) /* no such device */ 223*0Sstevel@tonic-gate return (ENXIO); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate switch (getminor(*devp)) { 226*0Sstevel@tonic-gate case USRMIN: /* mere mortal */ 227*0Sstevel@tonic-gate saddev[i].sa_flags = 0; 228*0Sstevel@tonic-gate break; 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate case ADMMIN: /* privileged user */ 231*0Sstevel@tonic-gate saddev[i].sa_flags = SADPRIV; 232*0Sstevel@tonic-gate break; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate default: 235*0Sstevel@tonic-gate return (EINVAL); 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate saddev[i].sa_qp = qp; 239*0Sstevel@tonic-gate qp->q_ptr = (caddr_t)&saddev[i]; 240*0Sstevel@tonic-gate WR(qp)->q_ptr = (caddr_t)&saddev[i]; 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate /* 243*0Sstevel@tonic-gate * NOTE: should the ADMMIN or USRMIN minors change 244*0Sstevel@tonic-gate * then so should the offset of 2 below 245*0Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces and 246*0Sstevel@tonic-gate * therefore their minor numbers (0 and 1) are reserved. 247*0Sstevel@tonic-gate */ 248*0Sstevel@tonic-gate *devp = makedevice(getemajor(*devp), i + 2); 249*0Sstevel@tonic-gate qprocson(qp); 250*0Sstevel@tonic-gate return (0); 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate /* 254*0Sstevel@tonic-gate * sadclose() - 255*0Sstevel@tonic-gate * Clean up the data structures. 256*0Sstevel@tonic-gate */ 257*0Sstevel@tonic-gate /* ARGSUSED */ 258*0Sstevel@tonic-gate static int 259*0Sstevel@tonic-gate sadclose( 260*0Sstevel@tonic-gate queue_t *qp, /* pointer to read queue */ 261*0Sstevel@tonic-gate int flag, /* file open flags */ 262*0Sstevel@tonic-gate cred_t *credp) /* user credentials */ 263*0Sstevel@tonic-gate { 264*0Sstevel@tonic-gate struct saddev *sadp; 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate qprocsoff(qp); 267*0Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 268*0Sstevel@tonic-gate sadp->sa_qp = NULL; 269*0Sstevel@tonic-gate sadp->sa_addr = NULL; 270*0Sstevel@tonic-gate qp->q_ptr = NULL; 271*0Sstevel@tonic-gate WR(qp)->q_ptr = NULL; 272*0Sstevel@tonic-gate return (0); 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate /* 276*0Sstevel@tonic-gate * sadwput() - 277*0Sstevel@tonic-gate * Write side put procedure. 278*0Sstevel@tonic-gate */ 279*0Sstevel@tonic-gate static int 280*0Sstevel@tonic-gate sadwput( 281*0Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 282*0Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 283*0Sstevel@tonic-gate { 284*0Sstevel@tonic-gate struct iocblk *iocp; 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 287*0Sstevel@tonic-gate case M_FLUSH: 288*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 289*0Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 290*0Sstevel@tonic-gate qreply(qp, mp); 291*0Sstevel@tonic-gate } else 292*0Sstevel@tonic-gate freemsg(mp); 293*0Sstevel@tonic-gate break; 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate case M_IOCTL: 296*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 297*0Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 298*0Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 299*0Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 300*0Sstevel@tonic-gate apush_ioctl(qp, mp); 301*0Sstevel@tonic-gate break; 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate case SAD_VML: 304*0Sstevel@tonic-gate vml_ioctl(qp, mp); 305*0Sstevel@tonic-gate break; 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate default: 308*0Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 309*0Sstevel@tonic-gate break; 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate break; 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate case M_IOCDATA: 314*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 315*0Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 316*0Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 317*0Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 318*0Sstevel@tonic-gate apush_iocdata(qp, mp); 319*0Sstevel@tonic-gate break; 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate case SAD_VML: 322*0Sstevel@tonic-gate vml_iocdata(qp, mp); 323*0Sstevel@tonic-gate break; 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate default: 326*0Sstevel@tonic-gate cmn_err(CE_WARN, 327*0Sstevel@tonic-gate "sadwput: invalid ioc_cmd in case M_IOCDATA: %d", 328*0Sstevel@tonic-gate iocp->ioc_cmd); 329*0Sstevel@tonic-gate freemsg(mp); 330*0Sstevel@tonic-gate break; 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate break; 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate default: 335*0Sstevel@tonic-gate freemsg(mp); 336*0Sstevel@tonic-gate break; 337*0Sstevel@tonic-gate } /* switch (db_type) */ 338*0Sstevel@tonic-gate return (0); 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate /* 342*0Sstevel@tonic-gate * apush_ioctl() - 343*0Sstevel@tonic-gate * Handle the M_IOCTL messages associated with 344*0Sstevel@tonic-gate * the autopush feature. 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate static void 347*0Sstevel@tonic-gate apush_ioctl( 348*0Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 349*0Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 350*0Sstevel@tonic-gate { 351*0Sstevel@tonic-gate struct iocblk *iocp; 352*0Sstevel@tonic-gate struct saddev *sadp; 353*0Sstevel@tonic-gate uint_t size; 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 356*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 357*0Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 358*0Sstevel@tonic-gate return; 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) > AP_VERSION) { 361*0Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 362*0Sstevel@tonic-gate return; 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 366*0Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 367*0Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 368*0Sstevel@tonic-gate if (!(sadp->sa_flags & SADPRIV)) { 369*0Sstevel@tonic-gate miocnak(qp, mp, 0, EPERM); 370*0Sstevel@tonic-gate break; 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate /* FALLTHRU */ 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 375*0Sstevel@tonic-gate sadp->sa_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 376*0Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) == 1) 377*0Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 378*0Sstevel@tonic-gate else 379*0Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 380*0Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, size, NULL); 381*0Sstevel@tonic-gate qreply(qp, mp); 382*0Sstevel@tonic-gate break; 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate default: 385*0Sstevel@tonic-gate ASSERT(0); 386*0Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 387*0Sstevel@tonic-gate break; 388*0Sstevel@tonic-gate } /* switch (ioc_cmd) */ 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate /* 392*0Sstevel@tonic-gate * apush_iocdata() - 393*0Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 394*0Sstevel@tonic-gate * the autopush feature. 395*0Sstevel@tonic-gate */ 396*0Sstevel@tonic-gate static void 397*0Sstevel@tonic-gate apush_iocdata( 398*0Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 399*0Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 400*0Sstevel@tonic-gate { 401*0Sstevel@tonic-gate int i, ret; 402*0Sstevel@tonic-gate struct copyresp *csp; 403*0Sstevel@tonic-gate struct strapush *sap; 404*0Sstevel@tonic-gate struct autopush *ap; 405*0Sstevel@tonic-gate struct saddev *sadp; 406*0Sstevel@tonic-gate uint_t size; 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 409*0Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 410*0Sstevel@tonic-gate freemsg(mp); 411*0Sstevel@tonic-gate return; 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate if (mp->b_cont) 414*0Sstevel@tonic-gate /* sap needed only if mp->b_cont is set */ 415*0Sstevel@tonic-gate sap = (struct strapush *)mp->b_cont->b_rptr; 416*0Sstevel@tonic-gate switch (SAD_CMD(csp->cp_cmd)) { 417*0Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 418*0Sstevel@tonic-gate switch ((long)csp->cp_private) { 419*0Sstevel@tonic-gate case GETSTRUCT: 420*0Sstevel@tonic-gate switch (sap->sap_cmd) { 421*0Sstevel@tonic-gate case SAP_ONE: 422*0Sstevel@tonic-gate case SAP_RANGE: 423*0Sstevel@tonic-gate case SAP_ALL: 424*0Sstevel@tonic-gate if ((sap->sap_npush == 0) || 425*0Sstevel@tonic-gate (sap->sap_npush > MAXAPUSH) || 426*0Sstevel@tonic-gate (sap->sap_npush > nstrpush)) { 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate /* invalid number of modules to push */ 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 431*0Sstevel@tonic-gate break; 432*0Sstevel@tonic-gate } 433*0Sstevel@tonic-gate if (ret = valid_major(sap->sap_major)) { 434*0Sstevel@tonic-gate miocnak(qp, mp, 0, ret); 435*0Sstevel@tonic-gate break; 436*0Sstevel@tonic-gate } 437*0Sstevel@tonic-gate if ((sap->sap_cmd == SAP_RANGE) && 438*0Sstevel@tonic-gate (sap->sap_lastminor <= sap->sap_minor)) { 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate /* bad range */ 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate miocnak(qp, mp, 0, ERANGE); 443*0Sstevel@tonic-gate break; 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate /* 447*0Sstevel@tonic-gate * Validate that the specified list of 448*0Sstevel@tonic-gate * modules exist. 449*0Sstevel@tonic-gate */ 450*0Sstevel@tonic-gate for (i = 0; i < sap->sap_npush; i++) { 451*0Sstevel@tonic-gate sap->sap_list[i][FMNAMESZ] = '\0'; 452*0Sstevel@tonic-gate if (fmodsw_find(sap->sap_list[i], 453*0Sstevel@tonic-gate FMODSW_LOAD) == NULL) { 454*0Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 455*0Sstevel@tonic-gate return; 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate mutex_enter(&sad_lock); 460*0Sstevel@tonic-gate if (ap_hfind(sap->sap_major, sap->sap_minor, 461*0Sstevel@tonic-gate sap->sap_lastminor, sap->sap_cmd)) { 462*0Sstevel@tonic-gate mutex_exit(&sad_lock); 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate /* already configured */ 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate miocnak(qp, mp, 0, EEXIST); 467*0Sstevel@tonic-gate break; 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate if ((ap = ap_alloc()) == NULL) { 470*0Sstevel@tonic-gate mutex_exit(&sad_lock); 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate /* no autopush structures */ 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate miocnak(qp, mp, 0, ENOSR); 475*0Sstevel@tonic-gate break; 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate ap->ap_cnt++; 478*0Sstevel@tonic-gate ap->ap_common = sap->sap_common; 479*0Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) > 0) 480*0Sstevel@tonic-gate ap->ap_anchor = sap->sap_anchor; 481*0Sstevel@tonic-gate else 482*0Sstevel@tonic-gate ap->ap_anchor = 0; 483*0Sstevel@tonic-gate for (i = 0; i < ap->ap_npush; i++) 484*0Sstevel@tonic-gate (void) strcpy(ap->ap_list[i], 485*0Sstevel@tonic-gate sap->sap_list[i]); 486*0Sstevel@tonic-gate ap_hadd(ap); 487*0Sstevel@tonic-gate mutex_exit(&sad_lock); 488*0Sstevel@tonic-gate miocack(qp, mp, 0, 0); 489*0Sstevel@tonic-gate break; 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate case SAP_CLEAR: 492*0Sstevel@tonic-gate if (ret = valid_major(sap->sap_major)) { 493*0Sstevel@tonic-gate miocnak(qp, mp, 0, ret); 494*0Sstevel@tonic-gate break; 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate mutex_enter(&sad_lock); 497*0Sstevel@tonic-gate if ((ap = ap_hfind(sap->sap_major, 498*0Sstevel@tonic-gate sap->sap_minor, sap->sap_lastminor, 499*0Sstevel@tonic-gate sap->sap_cmd)) == NULL) { 500*0Sstevel@tonic-gate mutex_exit(&sad_lock); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate /* not configured */ 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate miocnak(qp, mp, 0, ENODEV); 505*0Sstevel@tonic-gate break; 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate if ((ap->ap_type == SAP_RANGE) && 508*0Sstevel@tonic-gate (sap->sap_minor != ap->ap_minor)) { 509*0Sstevel@tonic-gate mutex_exit(&sad_lock); 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate /* starting minors do not match */ 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate miocnak(qp, mp, 0, ERANGE); 514*0Sstevel@tonic-gate break; 515*0Sstevel@tonic-gate } 516*0Sstevel@tonic-gate if ((ap->ap_type == SAP_ALL) && 517*0Sstevel@tonic-gate (sap->sap_minor != 0)) { 518*0Sstevel@tonic-gate mutex_exit(&sad_lock); 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate /* SAP_ALL must have minor == 0 */ 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 523*0Sstevel@tonic-gate break; 524*0Sstevel@tonic-gate } 525*0Sstevel@tonic-gate ap_hrmv(ap); 526*0Sstevel@tonic-gate if (--(ap->ap_cnt) <= 0) 527*0Sstevel@tonic-gate ap_free(ap); 528*0Sstevel@tonic-gate mutex_exit(&sad_lock); 529*0Sstevel@tonic-gate miocack(qp, mp, 0, 0); 530*0Sstevel@tonic-gate break; 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate default: 533*0Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 534*0Sstevel@tonic-gate break; 535*0Sstevel@tonic-gate } /* switch (sap_cmd) */ 536*0Sstevel@tonic-gate break; 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate default: 539*0Sstevel@tonic-gate cmn_err(CE_WARN, 540*0Sstevel@tonic-gate "apush_iocdata: cp_private bad in SAD_SAP: %p", 541*0Sstevel@tonic-gate (void *)csp->cp_private); 542*0Sstevel@tonic-gate freemsg(mp); 543*0Sstevel@tonic-gate break; 544*0Sstevel@tonic-gate } /* switch (cp_private) */ 545*0Sstevel@tonic-gate break; 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 548*0Sstevel@tonic-gate switch ((long)csp->cp_private) { 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate case GETSTRUCT: { 551*0Sstevel@tonic-gate if (ret = valid_major(sap->sap_major)) { 552*0Sstevel@tonic-gate miocnak(qp, mp, 0, ret); 553*0Sstevel@tonic-gate break; 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate mutex_enter(&sad_lock); 556*0Sstevel@tonic-gate if ((ap = ap_hfind(sap->sap_major, sap->sap_minor, 557*0Sstevel@tonic-gate sap->sap_lastminor, SAP_ONE)) == NULL) { 558*0Sstevel@tonic-gate mutex_exit(&sad_lock); 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate /* not configured */ 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate miocnak(qp, mp, 0, ENODEV); 563*0Sstevel@tonic-gate break; 564*0Sstevel@tonic-gate } 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate sap->sap_common = ap->ap_common; 567*0Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) > 0) 568*0Sstevel@tonic-gate sap->sap_anchor = ap->ap_anchor; 569*0Sstevel@tonic-gate for (i = 0; i < ap->ap_npush; i++) 570*0Sstevel@tonic-gate (void) strcpy(sap->sap_list[i], ap->ap_list[i]); 571*0Sstevel@tonic-gate for (; i < MAXAPUSH; i++) 572*0Sstevel@tonic-gate bzero(sap->sap_list[i], FMNAMESZ + 1); 573*0Sstevel@tonic-gate mutex_exit(&sad_lock); 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) == 1) 576*0Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 577*0Sstevel@tonic-gate else 578*0Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 581*0Sstevel@tonic-gate mcopyout(mp, (void *)GETRESULT, size, sadp->sa_addr, 582*0Sstevel@tonic-gate NULL); 583*0Sstevel@tonic-gate qreply(qp, mp); 584*0Sstevel@tonic-gate break; 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate case GETRESULT: 587*0Sstevel@tonic-gate miocack(qp, mp, 0, 0); 588*0Sstevel@tonic-gate break; 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate default: 591*0Sstevel@tonic-gate cmn_err(CE_WARN, 592*0Sstevel@tonic-gate "apush_iocdata: cp_private bad case SAD_GAP: %p", 593*0Sstevel@tonic-gate (void *)csp->cp_private); 594*0Sstevel@tonic-gate freemsg(mp); 595*0Sstevel@tonic-gate break; 596*0Sstevel@tonic-gate } /* switch (cp_private) */ 597*0Sstevel@tonic-gate break; 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate default: /* can't happen */ 600*0Sstevel@tonic-gate ASSERT(0); 601*0Sstevel@tonic-gate freemsg(mp); 602*0Sstevel@tonic-gate break; 603*0Sstevel@tonic-gate } /* switch (cp_cmd) */ 604*0Sstevel@tonic-gate } 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate /* 607*0Sstevel@tonic-gate * ap_alloc() - 608*0Sstevel@tonic-gate * Allocate an autopush structure. 609*0Sstevel@tonic-gate */ 610*0Sstevel@tonic-gate static struct autopush * 611*0Sstevel@tonic-gate ap_alloc(void) 612*0Sstevel@tonic-gate { 613*0Sstevel@tonic-gate struct autopush *ap; 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sad_lock)); 616*0Sstevel@tonic-gate if (strpfreep == NULL) 617*0Sstevel@tonic-gate return (NULL); 618*0Sstevel@tonic-gate ap = strpfreep; 619*0Sstevel@tonic-gate if (ap->ap_flags != APFREE) 620*0Sstevel@tonic-gate cmn_err(CE_PANIC, "ap_alloc: autopush struct not free: %d", 621*0Sstevel@tonic-gate ap->ap_flags); 622*0Sstevel@tonic-gate strpfreep = strpfreep->ap_nextp; 623*0Sstevel@tonic-gate ap->ap_nextp = NULL; 624*0Sstevel@tonic-gate ap->ap_flags = APUSED; 625*0Sstevel@tonic-gate return (ap); 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate /* 629*0Sstevel@tonic-gate * ap_free() - 630*0Sstevel@tonic-gate * Give an autopush structure back to the freelist. 631*0Sstevel@tonic-gate */ 632*0Sstevel@tonic-gate void 633*0Sstevel@tonic-gate ap_free(struct autopush *ap) 634*0Sstevel@tonic-gate { 635*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sad_lock)); 636*0Sstevel@tonic-gate if (!(ap->ap_flags & APUSED)) 637*0Sstevel@tonic-gate cmn_err(CE_PANIC, "ap_free: autopush struct not used: %d", 638*0Sstevel@tonic-gate ap->ap_flags); 639*0Sstevel@tonic-gate if (ap->ap_flags & APHASH) 640*0Sstevel@tonic-gate cmn_err(CE_PANIC, "ap_free: autopush struct not hashed: %d", 641*0Sstevel@tonic-gate ap->ap_flags); 642*0Sstevel@tonic-gate ap->ap_flags = APFREE; 643*0Sstevel@tonic-gate ap->ap_nextp = strpfreep; 644*0Sstevel@tonic-gate strpfreep = ap; 645*0Sstevel@tonic-gate } 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate /* 648*0Sstevel@tonic-gate * ap_hadd() - 649*0Sstevel@tonic-gate * Add an autopush structure to the hash list. 650*0Sstevel@tonic-gate */ 651*0Sstevel@tonic-gate static void 652*0Sstevel@tonic-gate ap_hadd(struct autopush *ap) 653*0Sstevel@tonic-gate { 654*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sad_lock)); 655*0Sstevel@tonic-gate if (!(ap->ap_flags & APUSED)) 656*0Sstevel@tonic-gate cmn_err(CE_PANIC, "ap_hadd: autopush struct not used: %d", 657*0Sstevel@tonic-gate ap->ap_flags); 658*0Sstevel@tonic-gate if (ap->ap_flags & APHASH) 659*0Sstevel@tonic-gate cmn_err(CE_PANIC, "ap_hadd: autopush struct not hashed: %d", 660*0Sstevel@tonic-gate ap->ap_flags); 661*0Sstevel@tonic-gate ap->ap_nextp = strphash(ap->ap_major); 662*0Sstevel@tonic-gate strphash(ap->ap_major) = ap; 663*0Sstevel@tonic-gate ap->ap_flags |= APHASH; 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate 666*0Sstevel@tonic-gate /* 667*0Sstevel@tonic-gate * ap_hrmv() - 668*0Sstevel@tonic-gate * Remove an autopush structure from the hash list. 669*0Sstevel@tonic-gate */ 670*0Sstevel@tonic-gate static void 671*0Sstevel@tonic-gate ap_hrmv(struct autopush *ap) 672*0Sstevel@tonic-gate { 673*0Sstevel@tonic-gate struct autopush *hap; 674*0Sstevel@tonic-gate struct autopush *prevp = NULL; 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sad_lock)); 677*0Sstevel@tonic-gate if (!(ap->ap_flags & APUSED)) 678*0Sstevel@tonic-gate cmn_err(CE_PANIC, "ap_hrmv: autopush struct not used: %d", 679*0Sstevel@tonic-gate ap->ap_flags); 680*0Sstevel@tonic-gate if (!(ap->ap_flags & APHASH)) 681*0Sstevel@tonic-gate cmn_err(CE_PANIC, "ap_hrmv: autopush struct not hashed: %d", 682*0Sstevel@tonic-gate ap->ap_flags); 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate hap = strphash(ap->ap_major); 685*0Sstevel@tonic-gate while (hap) { 686*0Sstevel@tonic-gate if (ap == hap) { 687*0Sstevel@tonic-gate hap->ap_flags &= ~APHASH; 688*0Sstevel@tonic-gate if (prevp) 689*0Sstevel@tonic-gate prevp->ap_nextp = hap->ap_nextp; 690*0Sstevel@tonic-gate else 691*0Sstevel@tonic-gate strphash(ap->ap_major) = hap->ap_nextp; 692*0Sstevel@tonic-gate return; 693*0Sstevel@tonic-gate } /* if */ 694*0Sstevel@tonic-gate prevp = hap; 695*0Sstevel@tonic-gate hap = hap->ap_nextp; 696*0Sstevel@tonic-gate } /* while */ 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate /* 700*0Sstevel@tonic-gate * ap_hfind() - 701*0Sstevel@tonic-gate * Look for an autopush structure in the hash list 702*0Sstevel@tonic-gate * based on major, minor, lastminor, and command. 703*0Sstevel@tonic-gate */ 704*0Sstevel@tonic-gate static struct autopush * 705*0Sstevel@tonic-gate ap_hfind( 706*0Sstevel@tonic-gate major_t maj, /* major device number */ 707*0Sstevel@tonic-gate minor_t minor, /* minor device number */ 708*0Sstevel@tonic-gate minor_t last, /* last minor device number (SAP_RANGE only) */ 709*0Sstevel@tonic-gate uint_t cmd) /* who is asking */ 710*0Sstevel@tonic-gate { 711*0Sstevel@tonic-gate struct autopush *ap; 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sad_lock)); 714*0Sstevel@tonic-gate ap = strphash(maj); 715*0Sstevel@tonic-gate while (ap) { 716*0Sstevel@tonic-gate if (ap->ap_major == maj) { 717*0Sstevel@tonic-gate if (cmd == SAP_ALL) 718*0Sstevel@tonic-gate break; 719*0Sstevel@tonic-gate switch (ap->ap_type) { 720*0Sstevel@tonic-gate case SAP_ALL: 721*0Sstevel@tonic-gate break; 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate case SAP_ONE: 724*0Sstevel@tonic-gate if (ap->ap_minor == minor) 725*0Sstevel@tonic-gate break; 726*0Sstevel@tonic-gate if ((cmd == SAP_RANGE) && 727*0Sstevel@tonic-gate (ap->ap_minor >= minor) && 728*0Sstevel@tonic-gate (ap->ap_minor <= last)) 729*0Sstevel@tonic-gate break; 730*0Sstevel@tonic-gate ap = ap->ap_nextp; 731*0Sstevel@tonic-gate continue; 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate case SAP_RANGE: 734*0Sstevel@tonic-gate if ((cmd == SAP_RANGE) && 735*0Sstevel@tonic-gate (((minor >= ap->ap_minor) && 736*0Sstevel@tonic-gate (minor <= ap->ap_lastminor)) || 737*0Sstevel@tonic-gate ((ap->ap_minor >= minor) && 738*0Sstevel@tonic-gate (ap->ap_minor <= last)))) 739*0Sstevel@tonic-gate break; 740*0Sstevel@tonic-gate if ((minor >= ap->ap_minor) && 741*0Sstevel@tonic-gate (minor <= ap->ap_lastminor)) 742*0Sstevel@tonic-gate break; 743*0Sstevel@tonic-gate ap = ap->ap_nextp; 744*0Sstevel@tonic-gate continue; 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate default: 747*0Sstevel@tonic-gate ASSERT(0); 748*0Sstevel@tonic-gate break; 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate break; 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate ap = ap->ap_nextp; 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate return (ap); 755*0Sstevel@tonic-gate } 756*0Sstevel@tonic-gate 757*0Sstevel@tonic-gate /* 758*0Sstevel@tonic-gate * vml_ioctl() - 759*0Sstevel@tonic-gate * Handle the M_IOCTL message associated with a request 760*0Sstevel@tonic-gate * to validate a module list. 761*0Sstevel@tonic-gate */ 762*0Sstevel@tonic-gate static void 763*0Sstevel@tonic-gate vml_ioctl( 764*0Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 765*0Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 766*0Sstevel@tonic-gate { 767*0Sstevel@tonic-gate struct iocblk *iocp; 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 770*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 771*0Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 772*0Sstevel@tonic-gate return; 773*0Sstevel@tonic-gate } 774*0Sstevel@tonic-gate ASSERT(iocp->ioc_cmd == SAD_VML); 775*0Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, 776*0Sstevel@tonic-gate SIZEOF_STRUCT(str_list, iocp->ioc_flag), NULL); 777*0Sstevel@tonic-gate qreply(qp, mp); 778*0Sstevel@tonic-gate } 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate /* 781*0Sstevel@tonic-gate * vml_iocdata() - 782*0Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 783*0Sstevel@tonic-gate * a request to validate a module list. 784*0Sstevel@tonic-gate */ 785*0Sstevel@tonic-gate static void 786*0Sstevel@tonic-gate vml_iocdata( 787*0Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 788*0Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 789*0Sstevel@tonic-gate { 790*0Sstevel@tonic-gate long i; 791*0Sstevel@tonic-gate int nmods; 792*0Sstevel@tonic-gate struct copyresp *csp; 793*0Sstevel@tonic-gate struct str_mlist *lp; 794*0Sstevel@tonic-gate STRUCT_HANDLE(str_list, slp); 795*0Sstevel@tonic-gate struct saddev *sadp; 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 798*0Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 799*0Sstevel@tonic-gate freemsg(mp); 800*0Sstevel@tonic-gate return; 801*0Sstevel@tonic-gate } 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gate ASSERT(csp->cp_cmd == SAD_VML); 804*0Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 805*0Sstevel@tonic-gate switch ((long)csp->cp_private) { 806*0Sstevel@tonic-gate case GETSTRUCT: 807*0Sstevel@tonic-gate STRUCT_SET_HANDLE(slp, csp->cp_flag, 808*0Sstevel@tonic-gate (struct str_list *)mp->b_cont->b_rptr); 809*0Sstevel@tonic-gate nmods = STRUCT_FGET(slp, sl_nmods); 810*0Sstevel@tonic-gate if (nmods <= 0) { 811*0Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 812*0Sstevel@tonic-gate break; 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate sadp->sa_addr = (caddr_t)(uintptr_t)nmods; 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate mcopyin(mp, (void *)GETLIST, nmods * sizeof (struct str_mlist), 817*0Sstevel@tonic-gate STRUCT_FGETP(slp, sl_modlist)); 818*0Sstevel@tonic-gate qreply(qp, mp); 819*0Sstevel@tonic-gate break; 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate case GETLIST: 822*0Sstevel@tonic-gate lp = (struct str_mlist *)mp->b_cont->b_rptr; 823*0Sstevel@tonic-gate for (i = 0; i < (long)sadp->sa_addr; i++, lp++) { 824*0Sstevel@tonic-gate lp->l_name[FMNAMESZ] = '\0'; 825*0Sstevel@tonic-gate if (fmodsw_find(lp->l_name, FMODSW_LOAD) == NULL) { 826*0Sstevel@tonic-gate miocack(qp, mp, 0, 1); 827*0Sstevel@tonic-gate return; 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate } 830*0Sstevel@tonic-gate miocack(qp, mp, 0, 0); 831*0Sstevel@tonic-gate break; 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate default: 834*0Sstevel@tonic-gate cmn_err(CE_WARN, "vml_iocdata: invalid cp_private value: %p", 835*0Sstevel@tonic-gate (void *)csp->cp_private); 836*0Sstevel@tonic-gate freemsg(mp); 837*0Sstevel@tonic-gate break; 838*0Sstevel@tonic-gate } /* switch (cp_private) */ 839*0Sstevel@tonic-gate } 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate /* 842*0Sstevel@tonic-gate * Validate a major number and also verify if 843*0Sstevel@tonic-gate * it is a STREAMS device. 844*0Sstevel@tonic-gate * Return values: 0 if a valid STREAMS dev 845*0Sstevel@tonic-gate * error code otherwise 846*0Sstevel@tonic-gate */ 847*0Sstevel@tonic-gate static int 848*0Sstevel@tonic-gate valid_major(major_t major) 849*0Sstevel@tonic-gate { 850*0Sstevel@tonic-gate int ret = 0; 851*0Sstevel@tonic-gate 852*0Sstevel@tonic-gate if (etoimajor(major) == -1) 853*0Sstevel@tonic-gate return (EINVAL); 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate /* 856*0Sstevel@tonic-gate * attempt to load the driver 'major' and verify that 857*0Sstevel@tonic-gate * it is a STREAMS driver. 858*0Sstevel@tonic-gate */ 859*0Sstevel@tonic-gate if (ddi_hold_driver(major) == NULL) 860*0Sstevel@tonic-gate return (EINVAL); 861*0Sstevel@tonic-gate 862*0Sstevel@tonic-gate if (!STREAMSTAB(major)) 863*0Sstevel@tonic-gate ret = ENOSTR; 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate ddi_rele_driver(major); 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate return (ret); 868*0Sstevel@tonic-gate } 869