17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51110f384Sedp * Common Development and Distribution License (the "License"). 61110f384Sedp * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22f4b3ec61Sdh155122 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 297c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate /* 337c478bd9Sstevel@tonic-gate * STREAMS Administrative Driver 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate * Currently only handles autopush and module name verification. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <sys/types.h> 397c478bd9Sstevel@tonic-gate #include <sys/param.h> 407c478bd9Sstevel@tonic-gate #include <sys/errno.h> 417c478bd9Sstevel@tonic-gate #include <sys/stream.h> 427c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 437c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 447c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 457c478bd9Sstevel@tonic-gate #include <sys/conf.h> 467c478bd9Sstevel@tonic-gate #include <sys/sad.h> 477c478bd9Sstevel@tonic-gate #include <sys/cred.h> 487c478bd9Sstevel@tonic-gate #include <sys/debug.h> 497c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 507c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 517c478bd9Sstevel@tonic-gate #include <sys/stat.h> 527c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 537c478bd9Sstevel@tonic-gate #include <sys/systm.h> 547c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 557c478bd9Sstevel@tonic-gate #include <sys/priv_names.h> 561110f384Sedp #include <sys/sysmacros.h> 57f4b3ec61Sdh155122 #include <sys/zone.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate static int sadopen(queue_t *, dev_t *, int, int, cred_t *); 607c478bd9Sstevel@tonic-gate static int sadclose(queue_t *, int, cred_t *); 617c478bd9Sstevel@tonic-gate static int sadwput(queue_t *qp, mblk_t *mp); 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate static int sad_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 647c478bd9Sstevel@tonic-gate static int sad_attach(dev_info_t *, ddi_attach_cmd_t); 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate static void apush_ioctl(), apush_iocdata(); 677c478bd9Sstevel@tonic-gate static void vml_ioctl(), vml_iocdata(); 687c478bd9Sstevel@tonic-gate static int valid_major(major_t); 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate static dev_info_t *sad_dip; /* private copy of devinfo pointer */ 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate static struct module_info sad_minfo = { 737c478bd9Sstevel@tonic-gate 0x7361, "sad", 0, INFPSZ, 0, 0 747c478bd9Sstevel@tonic-gate }; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static struct qinit sad_rinit = { 777c478bd9Sstevel@tonic-gate NULL, NULL, sadopen, sadclose, NULL, &sad_minfo, NULL 787c478bd9Sstevel@tonic-gate }; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate static struct qinit sad_winit = { 817c478bd9Sstevel@tonic-gate sadwput, NULL, NULL, NULL, NULL, &sad_minfo, NULL 827c478bd9Sstevel@tonic-gate }; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate struct streamtab sadinfo = { 857c478bd9Sstevel@tonic-gate &sad_rinit, &sad_winit, NULL, NULL 867c478bd9Sstevel@tonic-gate }; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(sad_ops, nulldev, nulldev, sad_attach, 89*d51110b7Sjfrank nodev, nodev, sad_info, 90*d51110b7Sjfrank D_MP | D_MTPERQ | D_MTOUTPERIM | D_MTOCEXCL, &sadinfo); 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 977c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 987c478bd9Sstevel@tonic-gate "STREAMS Administrative Driver 'sad' %I%", 997c478bd9Sstevel@tonic-gate &sad_ops, /* driver ops */ 1007c478bd9Sstevel@tonic-gate }; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1037c478bd9Sstevel@tonic-gate MODREV_1, &modldrv, NULL 1047c478bd9Sstevel@tonic-gate }; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate int 1077c478bd9Sstevel@tonic-gate _init(void) 1087c478bd9Sstevel@tonic-gate { 1097c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate int 1137c478bd9Sstevel@tonic-gate _fini(void) 1147c478bd9Sstevel@tonic-gate { 1157c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1167c478bd9Sstevel@tonic-gate } 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate int 1197c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1207c478bd9Sstevel@tonic-gate { 1217c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate static int 1257c478bd9Sstevel@tonic-gate sad_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 1267c478bd9Sstevel@tonic-gate { 1271110f384Sedp int instance = ddi_get_instance(devi); 1281110f384Sedp 1297c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 1307c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1317c478bd9Sstevel@tonic-gate 1321110f384Sedp ASSERT(instance == 0); 1331110f384Sedp if (instance != 0) 1341110f384Sedp return (DDI_FAILURE); 1351110f384Sedp 1367c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "user", S_IFCHR, 1377c478bd9Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 1387c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate if (ddi_create_priv_minor_node(devi, "admin", S_IFCHR, 1417c478bd9Sstevel@tonic-gate 1, DDI_PSEUDO, PRIVONLY_DEV, PRIV_SYS_CONFIG, 1427c478bd9Sstevel@tonic-gate PRIV_SYS_CONFIG, 0666) == DDI_FAILURE) { 1437c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 1447c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate sad_dip = devi; 1477c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1517c478bd9Sstevel@tonic-gate static int 1527c478bd9Sstevel@tonic-gate sad_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 1537c478bd9Sstevel@tonic-gate { 1547c478bd9Sstevel@tonic-gate int error; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate switch (infocmd) { 1577c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 1587c478bd9Sstevel@tonic-gate if (sad_dip == NULL) { 1597c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 1607c478bd9Sstevel@tonic-gate } else { 1617c478bd9Sstevel@tonic-gate *result = sad_dip; 1627c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate break; 1657c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 1667c478bd9Sstevel@tonic-gate *result = (void *)0; 1677c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 1687c478bd9Sstevel@tonic-gate break; 1697c478bd9Sstevel@tonic-gate default: 1707c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate return (error); 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* 1777c478bd9Sstevel@tonic-gate * sadopen() - 1787c478bd9Sstevel@tonic-gate * Allocate a sad device. Only one 1797c478bd9Sstevel@tonic-gate * open at a time allowed per device. 1807c478bd9Sstevel@tonic-gate */ 1817c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1827c478bd9Sstevel@tonic-gate static int 1837c478bd9Sstevel@tonic-gate sadopen( 1847c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to read queue */ 1857c478bd9Sstevel@tonic-gate dev_t *devp, /* major/minor device of stream */ 1867c478bd9Sstevel@tonic-gate int flag, /* file open flags */ 1877c478bd9Sstevel@tonic-gate int sflag, /* stream open flags */ 1887c478bd9Sstevel@tonic-gate cred_t *credp) /* user credentials */ 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate int i; 191f4b3ec61Sdh155122 netstack_t *ns; 192f4b3ec61Sdh155122 str_stack_t *ss; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if (sflag) /* no longer called from clone driver */ 1957c478bd9Sstevel@tonic-gate return (EINVAL); 1967c478bd9Sstevel@tonic-gate 197f4b3ec61Sdh155122 ns = netstack_find_by_cred(credp); 198f4b3ec61Sdh155122 ASSERT(ns != NULL); 199f4b3ec61Sdh155122 ss = ns->netstack_str; 200f4b3ec61Sdh155122 ASSERT(ss != NULL); 201f4b3ec61Sdh155122 2027c478bd9Sstevel@tonic-gate /* 2037c478bd9Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces. 2047c478bd9Sstevel@tonic-gate */ 205f4b3ec61Sdh155122 for (i = 0; i < ss->ss_sadcnt; i++) 206f4b3ec61Sdh155122 if (ss->ss_saddev[i].sa_qp == NULL) 2077c478bd9Sstevel@tonic-gate break; 208f4b3ec61Sdh155122 if (i >= ss->ss_sadcnt) { /* no such device */ 209f4b3ec61Sdh155122 netstack_rele(ss->ss_netstack); 2107c478bd9Sstevel@tonic-gate return (ENXIO); 211f4b3ec61Sdh155122 } 2127c478bd9Sstevel@tonic-gate switch (getminor(*devp)) { 2137c478bd9Sstevel@tonic-gate case USRMIN: /* mere mortal */ 214f4b3ec61Sdh155122 ss->ss_saddev[i].sa_flags = 0; 2157c478bd9Sstevel@tonic-gate break; 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate case ADMMIN: /* privileged user */ 218f4b3ec61Sdh155122 ss->ss_saddev[i].sa_flags = SADPRIV; 2197c478bd9Sstevel@tonic-gate break; 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate default: 222f4b3ec61Sdh155122 netstack_rele(ss->ss_netstack); 2237c478bd9Sstevel@tonic-gate return (EINVAL); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 226f4b3ec61Sdh155122 ss->ss_saddev[i].sa_qp = qp; 227f4b3ec61Sdh155122 ss->ss_saddev[i].sa_ss = ss; 228f4b3ec61Sdh155122 qp->q_ptr = (caddr_t)&ss->ss_saddev[i]; 229f4b3ec61Sdh155122 WR(qp)->q_ptr = (caddr_t)&ss->ss_saddev[i]; 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate /* 2327c478bd9Sstevel@tonic-gate * NOTE: should the ADMMIN or USRMIN minors change 2337c478bd9Sstevel@tonic-gate * then so should the offset of 2 below 2347c478bd9Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces and 2357c478bd9Sstevel@tonic-gate * therefore their minor numbers (0 and 1) are reserved. 2367c478bd9Sstevel@tonic-gate */ 2377c478bd9Sstevel@tonic-gate *devp = makedevice(getemajor(*devp), i + 2); 2387c478bd9Sstevel@tonic-gate qprocson(qp); 2397c478bd9Sstevel@tonic-gate return (0); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* 2437c478bd9Sstevel@tonic-gate * sadclose() - 2447c478bd9Sstevel@tonic-gate * Clean up the data structures. 2457c478bd9Sstevel@tonic-gate */ 2467c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2477c478bd9Sstevel@tonic-gate static int 2487c478bd9Sstevel@tonic-gate sadclose( 2497c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to read queue */ 2507c478bd9Sstevel@tonic-gate int flag, /* file open flags */ 2517c478bd9Sstevel@tonic-gate cred_t *credp) /* user credentials */ 2527c478bd9Sstevel@tonic-gate { 2537c478bd9Sstevel@tonic-gate struct saddev *sadp; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate qprocsoff(qp); 2567c478bd9Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 2577c478bd9Sstevel@tonic-gate sadp->sa_qp = NULL; 2587c478bd9Sstevel@tonic-gate sadp->sa_addr = NULL; 259f4b3ec61Sdh155122 netstack_rele(sadp->sa_ss->ss_netstack); 260f4b3ec61Sdh155122 sadp->sa_ss = NULL; 2617c478bd9Sstevel@tonic-gate qp->q_ptr = NULL; 2627c478bd9Sstevel@tonic-gate WR(qp)->q_ptr = NULL; 2637c478bd9Sstevel@tonic-gate return (0); 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * sadwput() - 2687c478bd9Sstevel@tonic-gate * Write side put procedure. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate static int 2717c478bd9Sstevel@tonic-gate sadwput( 2727c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 2737c478bd9Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 2747c478bd9Sstevel@tonic-gate { 2757c478bd9Sstevel@tonic-gate struct iocblk *iocp; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 2787c478bd9Sstevel@tonic-gate case M_FLUSH: 2797c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 2807c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 2817c478bd9Sstevel@tonic-gate qreply(qp, mp); 2827c478bd9Sstevel@tonic-gate } else 2837c478bd9Sstevel@tonic-gate freemsg(mp); 2847c478bd9Sstevel@tonic-gate break; 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate case M_IOCTL: 2877c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 2887c478bd9Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 2897c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 2907c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 2917c478bd9Sstevel@tonic-gate apush_ioctl(qp, mp); 2927c478bd9Sstevel@tonic-gate break; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate case SAD_VML: 2957c478bd9Sstevel@tonic-gate vml_ioctl(qp, mp); 2967c478bd9Sstevel@tonic-gate break; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate default: 2997c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3007c478bd9Sstevel@tonic-gate break; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate break; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate case M_IOCDATA: 3057c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3067c478bd9Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 3077c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 3087c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 3097c478bd9Sstevel@tonic-gate apush_iocdata(qp, mp); 3107c478bd9Sstevel@tonic-gate break; 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate case SAD_VML: 3137c478bd9Sstevel@tonic-gate vml_iocdata(qp, mp); 3147c478bd9Sstevel@tonic-gate break; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate default: 3177c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 3187c478bd9Sstevel@tonic-gate "sadwput: invalid ioc_cmd in case M_IOCDATA: %d", 3197c478bd9Sstevel@tonic-gate iocp->ioc_cmd); 3207c478bd9Sstevel@tonic-gate freemsg(mp); 3217c478bd9Sstevel@tonic-gate break; 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate break; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate default: 3267c478bd9Sstevel@tonic-gate freemsg(mp); 3277c478bd9Sstevel@tonic-gate break; 3287c478bd9Sstevel@tonic-gate } /* switch (db_type) */ 3297c478bd9Sstevel@tonic-gate return (0); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * apush_ioctl() - 3347c478bd9Sstevel@tonic-gate * Handle the M_IOCTL messages associated with 3357c478bd9Sstevel@tonic-gate * the autopush feature. 3367c478bd9Sstevel@tonic-gate */ 3377c478bd9Sstevel@tonic-gate static void 3387c478bd9Sstevel@tonic-gate apush_ioctl( 3397c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 3407c478bd9Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 3417c478bd9Sstevel@tonic-gate { 3427c478bd9Sstevel@tonic-gate struct iocblk *iocp; 3437c478bd9Sstevel@tonic-gate struct saddev *sadp; 3447c478bd9Sstevel@tonic-gate uint_t size; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3477c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 3487c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3497c478bd9Sstevel@tonic-gate return; 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) > AP_VERSION) { 3527c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3537c478bd9Sstevel@tonic-gate return; 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 3577c478bd9Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 3587c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 3597c478bd9Sstevel@tonic-gate if (!(sadp->sa_flags & SADPRIV)) { 3607c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EPERM); 3617c478bd9Sstevel@tonic-gate break; 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate /* FALLTHRU */ 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 3667c478bd9Sstevel@tonic-gate sadp->sa_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 3677c478bd9Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) == 1) 3687c478bd9Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 3697c478bd9Sstevel@tonic-gate else 3707c478bd9Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 3717c478bd9Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, size, NULL); 3727c478bd9Sstevel@tonic-gate qreply(qp, mp); 3737c478bd9Sstevel@tonic-gate break; 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate default: 3767c478bd9Sstevel@tonic-gate ASSERT(0); 3777c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3787c478bd9Sstevel@tonic-gate break; 3797c478bd9Sstevel@tonic-gate } /* switch (ioc_cmd) */ 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* 3837c478bd9Sstevel@tonic-gate * apush_iocdata() - 3847c478bd9Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 3857c478bd9Sstevel@tonic-gate * the autopush feature. 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate static void 3887c478bd9Sstevel@tonic-gate apush_iocdata( 3897c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 3907c478bd9Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 3917c478bd9Sstevel@tonic-gate { 3927c478bd9Sstevel@tonic-gate int i, ret; 3937c478bd9Sstevel@tonic-gate struct copyresp *csp; 3944121995cSedp struct strapush *sap = NULL; 3951110f384Sedp struct autopush *ap, *ap_tmp; 3967c478bd9Sstevel@tonic-gate struct saddev *sadp; 3977c478bd9Sstevel@tonic-gate uint_t size; 3981110f384Sedp dev_t dev; 399f4b3ec61Sdh155122 str_stack_t *ss; 400f4b3ec61Sdh155122 401f4b3ec61Sdh155122 sadp = (struct saddev *)qp->q_ptr; 402f4b3ec61Sdh155122 ss = sadp->sa_ss; 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 4057c478bd9Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 4067c478bd9Sstevel@tonic-gate freemsg(mp); 4077c478bd9Sstevel@tonic-gate return; 4087c478bd9Sstevel@tonic-gate } 4091110f384Sedp if (mp->b_cont) { 4107c478bd9Sstevel@tonic-gate /* 4114121995cSedp * sap needed only if mp->b_cont is set. figure out the 4124121995cSedp * size of the expected sap structure and make sure 4134121995cSedp * enough data was supplied. 4147c478bd9Sstevel@tonic-gate */ 4154121995cSedp if (SAD_VER(csp->cp_cmd) == 1) 4164121995cSedp size = STRAPUSH_V1_LEN; 4174121995cSedp else 4184121995cSedp size = STRAPUSH_V0_LEN; 4194121995cSedp if (MBLKL(mp->b_cont) < size) { 4204121995cSedp miocnak(qp, mp, 0, EINVAL); 4217c478bd9Sstevel@tonic-gate return; 4227c478bd9Sstevel@tonic-gate } 4231110f384Sedp sap = (struct strapush *)mp->b_cont->b_rptr; 4241110f384Sedp dev = makedevice(sap->sap_major, sap->sap_minor); 4257c478bd9Sstevel@tonic-gate } 4261110f384Sedp switch (SAD_CMD(csp->cp_cmd)) { 4271110f384Sedp case SAD_CMD(SAD_SAP): 4287c478bd9Sstevel@tonic-gate 4291110f384Sedp /* currently we only support one SAD_SAP command */ 4301110f384Sedp if (((long)csp->cp_private) != GETSTRUCT) { 4317c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 4327c478bd9Sstevel@tonic-gate "apush_iocdata: cp_private bad in SAD_SAP: %p", 4337c478bd9Sstevel@tonic-gate (void *)csp->cp_private); 4341110f384Sedp miocnak(qp, mp, 0, EINVAL); 4351110f384Sedp return; 4361110f384Sedp } 4371110f384Sedp 4381110f384Sedp switch (sap->sap_cmd) { 4391110f384Sedp default: 4401110f384Sedp miocnak(qp, mp, 0, EINVAL); 4411110f384Sedp return; 4421110f384Sedp case SAP_ONE: 4431110f384Sedp case SAP_RANGE: 4441110f384Sedp case SAP_ALL: 4451110f384Sedp /* allocate and initialize a new config */ 4461110f384Sedp ap = sad_ap_alloc(); 4471110f384Sedp ap->ap_common = sap->sap_common; 4481110f384Sedp if (SAD_VER(csp->cp_cmd) > 0) 4491110f384Sedp ap->ap_anchor = sap->sap_anchor; 4501110f384Sedp for (i = 0; i < MIN(sap->sap_npush, MAXAPUSH); i++) 4511110f384Sedp (void) strncpy(ap->ap_list[i], 4521110f384Sedp sap->sap_list[i], FMNAMESZ); 4531110f384Sedp 4541110f384Sedp /* sanity check the request */ 4551110f384Sedp if (((ret = sad_ap_verify(ap)) != 0) || 4561110f384Sedp ((ret = valid_major(ap->ap_major)) != 0)) { 457f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 4581110f384Sedp miocnak(qp, mp, 0, ret); 4591110f384Sedp return; 4601110f384Sedp } 4611110f384Sedp 4621110f384Sedp /* check for overlapping configs */ 463f4b3ec61Sdh155122 mutex_enter(&ss->ss_sad_lock); 464f4b3ec61Sdh155122 ap_tmp = sad_ap_find(&ap->ap_common, ss); 465f4b3ec61Sdh155122 if (ap_tmp != NULL) { 4661110f384Sedp /* already configured */ 467f4b3ec61Sdh155122 mutex_exit(&ss->ss_sad_lock); 468f4b3ec61Sdh155122 sad_ap_rele(ap_tmp, ss); 469f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 4701110f384Sedp miocnak(qp, mp, 0, EEXIST); 4711110f384Sedp return; 4721110f384Sedp } 4731110f384Sedp 4741110f384Sedp /* add the new config to our hash */ 475f4b3ec61Sdh155122 sad_ap_insert(ap, ss); 476f4b3ec61Sdh155122 mutex_exit(&ss->ss_sad_lock); 4771110f384Sedp miocack(qp, mp, 0, 0); 4781110f384Sedp return; 4791110f384Sedp 4801110f384Sedp case SAP_CLEAR: 4811110f384Sedp /* sanity check the request */ 4821110f384Sedp if (ret = valid_major(sap->sap_major)) { 4831110f384Sedp miocnak(qp, mp, 0, ret); 4841110f384Sedp return; 4851110f384Sedp } 4861110f384Sedp 4871110f384Sedp /* search for a matching config */ 488f4b3ec61Sdh155122 if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { 4891110f384Sedp /* no config found */ 4901110f384Sedp miocnak(qp, mp, 0, ENODEV); 4911110f384Sedp return; 4921110f384Sedp } 4931110f384Sedp 4941110f384Sedp /* 4951110f384Sedp * If we matched a SAP_RANGE config 4961110f384Sedp * the minor passed in must match the 4971110f384Sedp * beginning of the range exactly. 4981110f384Sedp */ 4991110f384Sedp if ((ap->ap_type == SAP_RANGE) && 5001110f384Sedp (ap->ap_minor != sap->sap_minor)) { 501f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 5021110f384Sedp miocnak(qp, mp, 0, ERANGE); 5031110f384Sedp return; 5041110f384Sedp } 5051110f384Sedp 5061110f384Sedp /* 5071110f384Sedp * If we matched a SAP_ALL config 5081110f384Sedp * the minor passed in must be 0. 5091110f384Sedp */ 5101110f384Sedp if ((ap->ap_type == SAP_ALL) && 5111110f384Sedp (sap->sap_minor != 0)) { 512f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 5131110f384Sedp miocnak(qp, mp, 0, EINVAL); 5141110f384Sedp return; 5151110f384Sedp } 5161110f384Sedp 5171110f384Sedp /* 5181110f384Sedp * make sure someone else hasn't already 5191110f384Sedp * removed this config from the hash. 5201110f384Sedp */ 521f4b3ec61Sdh155122 mutex_enter(&ss->ss_sad_lock); 522f4b3ec61Sdh155122 ap_tmp = sad_ap_find(&ap->ap_common, ss); 5231110f384Sedp if (ap_tmp != ap) { 524f4b3ec61Sdh155122 mutex_exit(&ss->ss_sad_lock); 525f4b3ec61Sdh155122 sad_ap_rele(ap_tmp, ss); 526f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 5271110f384Sedp miocnak(qp, mp, 0, ENODEV); 5281110f384Sedp return; 529f4b3ec61Sdh155122 } 5301110f384Sedp 5311110f384Sedp /* remove the config from the hash and return */ 532f4b3ec61Sdh155122 sad_ap_remove(ap, ss); 533f4b3ec61Sdh155122 mutex_exit(&ss->ss_sad_lock); 5341110f384Sedp 5351110f384Sedp /* 5361110f384Sedp * Release thrice, once for sad_ap_find_by_dev(), 5371110f384Sedp * once for sad_ap_find(), and once to free. 5381110f384Sedp */ 539f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 540f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 541f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 5421110f384Sedp miocack(qp, mp, 0, 0); 5431110f384Sedp return; 5441110f384Sedp } /* switch (sap_cmd) */ 5451110f384Sedp /*NOTREACHED*/ 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 5487c478bd9Sstevel@tonic-gate switch ((long)csp->cp_private) { 5497c478bd9Sstevel@tonic-gate 5501110f384Sedp case GETSTRUCT: 5511110f384Sedp /* sanity check the request */ 5527c478bd9Sstevel@tonic-gate if (ret = valid_major(sap->sap_major)) { 5537c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, ret); 5541110f384Sedp return; 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5571110f384Sedp /* search for a matching config */ 558f4b3ec61Sdh155122 if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { 5591110f384Sedp /* no config found */ 5607c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, ENODEV); 5611110f384Sedp return; 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5641110f384Sedp /* copy out the contents of the config */ 5657c478bd9Sstevel@tonic-gate sap->sap_common = ap->ap_common; 5667c478bd9Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) > 0) 5677c478bd9Sstevel@tonic-gate sap->sap_anchor = ap->ap_anchor; 5687c478bd9Sstevel@tonic-gate for (i = 0; i < ap->ap_npush; i++) 5697c478bd9Sstevel@tonic-gate (void) strcpy(sap->sap_list[i], ap->ap_list[i]); 5707c478bd9Sstevel@tonic-gate for (; i < MAXAPUSH; i++) 5717c478bd9Sstevel@tonic-gate bzero(sap->sap_list[i], FMNAMESZ + 1); 5727c478bd9Sstevel@tonic-gate 5731110f384Sedp /* release our hold on the config */ 574f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 5751110f384Sedp 5761110f384Sedp /* copyout the results */ 5777c478bd9Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) == 1) 5787c478bd9Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 5797c478bd9Sstevel@tonic-gate else 5807c478bd9Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate mcopyout(mp, (void *)GETRESULT, size, sadp->sa_addr, 5837c478bd9Sstevel@tonic-gate NULL); 5847c478bd9Sstevel@tonic-gate qreply(qp, mp); 5851110f384Sedp return; 5867c478bd9Sstevel@tonic-gate case GETRESULT: 5877c478bd9Sstevel@tonic-gate miocack(qp, mp, 0, 0); 5881110f384Sedp return; 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate default: 5917c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 5927c478bd9Sstevel@tonic-gate "apush_iocdata: cp_private bad case SAD_GAP: %p", 5937c478bd9Sstevel@tonic-gate (void *)csp->cp_private); 5947c478bd9Sstevel@tonic-gate freemsg(mp); 5951110f384Sedp return; 5967c478bd9Sstevel@tonic-gate } /* switch (cp_private) */ 5971110f384Sedp /*NOTREACHED*/ 5987c478bd9Sstevel@tonic-gate default: /* can't happen */ 5997c478bd9Sstevel@tonic-gate ASSERT(0); 6007c478bd9Sstevel@tonic-gate freemsg(mp); 6017c478bd9Sstevel@tonic-gate return; 6021110f384Sedp } /* switch (cp_cmd) */ 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /* 6067c478bd9Sstevel@tonic-gate * vml_ioctl() - 6077c478bd9Sstevel@tonic-gate * Handle the M_IOCTL message associated with a request 6087c478bd9Sstevel@tonic-gate * to validate a module list. 6097c478bd9Sstevel@tonic-gate */ 6107c478bd9Sstevel@tonic-gate static void 6117c478bd9Sstevel@tonic-gate vml_ioctl( 6127c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 6137c478bd9Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 6147c478bd9Sstevel@tonic-gate { 6157c478bd9Sstevel@tonic-gate struct iocblk *iocp; 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 6187c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 6197c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 6207c478bd9Sstevel@tonic-gate return; 6217c478bd9Sstevel@tonic-gate } 62264248fb8Sethindra ASSERT(SAD_CMD(iocp->ioc_cmd) == SAD_VML); 6237c478bd9Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, 6247c478bd9Sstevel@tonic-gate SIZEOF_STRUCT(str_list, iocp->ioc_flag), NULL); 6257c478bd9Sstevel@tonic-gate qreply(qp, mp); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate /* 6297c478bd9Sstevel@tonic-gate * vml_iocdata() - 6307c478bd9Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 6317c478bd9Sstevel@tonic-gate * a request to validate a module list. 6327c478bd9Sstevel@tonic-gate */ 6337c478bd9Sstevel@tonic-gate static void 6347c478bd9Sstevel@tonic-gate vml_iocdata( 6357c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 6367c478bd9Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 6377c478bd9Sstevel@tonic-gate { 6387c478bd9Sstevel@tonic-gate long i; 6397c478bd9Sstevel@tonic-gate int nmods; 6407c478bd9Sstevel@tonic-gate struct copyresp *csp; 6417c478bd9Sstevel@tonic-gate struct str_mlist *lp; 6427c478bd9Sstevel@tonic-gate STRUCT_HANDLE(str_list, slp); 6437c478bd9Sstevel@tonic-gate struct saddev *sadp; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 6467c478bd9Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 6477c478bd9Sstevel@tonic-gate freemsg(mp); 6487c478bd9Sstevel@tonic-gate return; 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 65164248fb8Sethindra ASSERT(SAD_CMD(csp->cp_cmd) == SAD_VML); 6527c478bd9Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 6537c478bd9Sstevel@tonic-gate switch ((long)csp->cp_private) { 6547c478bd9Sstevel@tonic-gate case GETSTRUCT: 6557c478bd9Sstevel@tonic-gate STRUCT_SET_HANDLE(slp, csp->cp_flag, 6567c478bd9Sstevel@tonic-gate (struct str_list *)mp->b_cont->b_rptr); 6577c478bd9Sstevel@tonic-gate nmods = STRUCT_FGET(slp, sl_nmods); 6587c478bd9Sstevel@tonic-gate if (nmods <= 0) { 6597c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 6607c478bd9Sstevel@tonic-gate break; 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate sadp->sa_addr = (caddr_t)(uintptr_t)nmods; 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate mcopyin(mp, (void *)GETLIST, nmods * sizeof (struct str_mlist), 6657c478bd9Sstevel@tonic-gate STRUCT_FGETP(slp, sl_modlist)); 6667c478bd9Sstevel@tonic-gate qreply(qp, mp); 6677c478bd9Sstevel@tonic-gate break; 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate case GETLIST: 6707c478bd9Sstevel@tonic-gate lp = (struct str_mlist *)mp->b_cont->b_rptr; 6717c478bd9Sstevel@tonic-gate for (i = 0; i < (long)sadp->sa_addr; i++, lp++) { 6727c478bd9Sstevel@tonic-gate lp->l_name[FMNAMESZ] = '\0'; 6737c478bd9Sstevel@tonic-gate if (fmodsw_find(lp->l_name, FMODSW_LOAD) == NULL) { 6747c478bd9Sstevel@tonic-gate miocack(qp, mp, 0, 1); 6757c478bd9Sstevel@tonic-gate return; 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate miocack(qp, mp, 0, 0); 6797c478bd9Sstevel@tonic-gate break; 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate default: 6827c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "vml_iocdata: invalid cp_private value: %p", 6837c478bd9Sstevel@tonic-gate (void *)csp->cp_private); 6847c478bd9Sstevel@tonic-gate freemsg(mp); 6857c478bd9Sstevel@tonic-gate break; 6867c478bd9Sstevel@tonic-gate } /* switch (cp_private) */ 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate /* 6907c478bd9Sstevel@tonic-gate * Validate a major number and also verify if 6917c478bd9Sstevel@tonic-gate * it is a STREAMS device. 6927c478bd9Sstevel@tonic-gate * Return values: 0 if a valid STREAMS dev 6937c478bd9Sstevel@tonic-gate * error code otherwise 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate static int 6967c478bd9Sstevel@tonic-gate valid_major(major_t major) 6977c478bd9Sstevel@tonic-gate { 6987c478bd9Sstevel@tonic-gate int ret = 0; 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate if (etoimajor(major) == -1) 7017c478bd9Sstevel@tonic-gate return (EINVAL); 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate /* 7047c478bd9Sstevel@tonic-gate * attempt to load the driver 'major' and verify that 7057c478bd9Sstevel@tonic-gate * it is a STREAMS driver. 7067c478bd9Sstevel@tonic-gate */ 7077c478bd9Sstevel@tonic-gate if (ddi_hold_driver(major) == NULL) 7087c478bd9Sstevel@tonic-gate return (EINVAL); 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate if (!STREAMSTAB(major)) 7117c478bd9Sstevel@tonic-gate ret = ENOSTR; 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate ddi_rele_driver(major); 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate return (ret); 7167c478bd9Sstevel@tonic-gate } 717