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 /* 22*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate /* 327c478bd9Sstevel@tonic-gate * STREAMS Administrative Driver 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * Currently only handles autopush and module name verification. 357c478bd9Sstevel@tonic-gate */ 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <sys/types.h> 387c478bd9Sstevel@tonic-gate #include <sys/param.h> 397c478bd9Sstevel@tonic-gate #include <sys/errno.h> 407c478bd9Sstevel@tonic-gate #include <sys/stream.h> 417c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 427c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 437c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 447c478bd9Sstevel@tonic-gate #include <sys/conf.h> 457c478bd9Sstevel@tonic-gate #include <sys/sad.h> 467c478bd9Sstevel@tonic-gate #include <sys/cred.h> 477c478bd9Sstevel@tonic-gate #include <sys/debug.h> 487c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 497c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 507c478bd9Sstevel@tonic-gate #include <sys/stat.h> 517c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 527c478bd9Sstevel@tonic-gate #include <sys/systm.h> 537c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 541110f384Sedp #include <sys/sysmacros.h> 55f4b3ec61Sdh155122 #include <sys/zone.h> 56e6bdcbd5Sdh155122 #include <sys/policy.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate static int sadopen(queue_t *, dev_t *, int, int, cred_t *); 597c478bd9Sstevel@tonic-gate static int sadclose(queue_t *, int, cred_t *); 607c478bd9Sstevel@tonic-gate static int sadwput(queue_t *qp, mblk_t *mp); 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate static int sad_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 637c478bd9Sstevel@tonic-gate static int sad_attach(dev_info_t *, ddi_attach_cmd_t); 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate static void apush_ioctl(), apush_iocdata(); 667c478bd9Sstevel@tonic-gate static void vml_ioctl(), vml_iocdata(); 677c478bd9Sstevel@tonic-gate static int valid_major(major_t); 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate static dev_info_t *sad_dip; /* private copy of devinfo pointer */ 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate static struct module_info sad_minfo = { 727c478bd9Sstevel@tonic-gate 0x7361, "sad", 0, INFPSZ, 0, 0 737c478bd9Sstevel@tonic-gate }; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate static struct qinit sad_rinit = { 767c478bd9Sstevel@tonic-gate NULL, NULL, sadopen, sadclose, NULL, &sad_minfo, NULL 777c478bd9Sstevel@tonic-gate }; 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate static struct qinit sad_winit = { 807c478bd9Sstevel@tonic-gate sadwput, NULL, NULL, NULL, NULL, &sad_minfo, NULL 817c478bd9Sstevel@tonic-gate }; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate struct streamtab sadinfo = { 847c478bd9Sstevel@tonic-gate &sad_rinit, &sad_winit, NULL, NULL 857c478bd9Sstevel@tonic-gate }; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(sad_ops, nulldev, nulldev, sad_attach, 88d51110b7Sjfrank nodev, nodev, sad_info, 89*19397407SSherry Moore D_MP | D_MTPERQ | D_MTOUTPERIM | D_MTOCEXCL, &sadinfo, 90*19397407SSherry Moore ddi_quiesce_not_supported); 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 */ 98e6bdcbd5Sdh155122 "STREAMS Administrative Driver 'sad'", 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 } 140e6bdcbd5Sdh155122 if (ddi_create_minor_node(devi, "admin", S_IFCHR, 141e6bdcbd5Sdh155122 1, DDI_PSEUDO, NULL) == DDI_FAILURE) { 1427c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 1437c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate sad_dip = devi; 1467c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1507c478bd9Sstevel@tonic-gate static int 1517c478bd9Sstevel@tonic-gate sad_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 1527c478bd9Sstevel@tonic-gate { 1537c478bd9Sstevel@tonic-gate int error; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate switch (infocmd) { 1567c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 1577c478bd9Sstevel@tonic-gate if (sad_dip == NULL) { 1587c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 1597c478bd9Sstevel@tonic-gate } else { 1607c478bd9Sstevel@tonic-gate *result = sad_dip; 1617c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate break; 1647c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 1657c478bd9Sstevel@tonic-gate *result = (void *)0; 1667c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 1677c478bd9Sstevel@tonic-gate break; 1687c478bd9Sstevel@tonic-gate default: 1697c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate return (error); 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate /* 1767c478bd9Sstevel@tonic-gate * sadopen() - 1777c478bd9Sstevel@tonic-gate * Allocate a sad device. Only one 1787c478bd9Sstevel@tonic-gate * open at a time allowed per device. 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1817c478bd9Sstevel@tonic-gate static int 1827c478bd9Sstevel@tonic-gate sadopen( 1837c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to read queue */ 1847c478bd9Sstevel@tonic-gate dev_t *devp, /* major/minor device of stream */ 1857c478bd9Sstevel@tonic-gate int flag, /* file open flags */ 1867c478bd9Sstevel@tonic-gate int sflag, /* stream open flags */ 1877c478bd9Sstevel@tonic-gate cred_t *credp) /* user credentials */ 1887c478bd9Sstevel@tonic-gate { 1897c478bd9Sstevel@tonic-gate int i; 190f4b3ec61Sdh155122 netstack_t *ns; 191f4b3ec61Sdh155122 str_stack_t *ss; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate if (sflag) /* no longer called from clone driver */ 1947c478bd9Sstevel@tonic-gate return (EINVAL); 1957c478bd9Sstevel@tonic-gate 196e6bdcbd5Sdh155122 /* Only privileged process can access ADMINDEV */ 197e6bdcbd5Sdh155122 if (getminor(*devp) == ADMMIN) { 198e6bdcbd5Sdh155122 int err; 199e6bdcbd5Sdh155122 200e6bdcbd5Sdh155122 err = secpolicy_sadopen(credp); 201e6bdcbd5Sdh155122 202e6bdcbd5Sdh155122 if (err != 0) 203e6bdcbd5Sdh155122 return (err); 204e6bdcbd5Sdh155122 } 205e6bdcbd5Sdh155122 206f4b3ec61Sdh155122 ns = netstack_find_by_cred(credp); 207f4b3ec61Sdh155122 ASSERT(ns != NULL); 208f4b3ec61Sdh155122 ss = ns->netstack_str; 209f4b3ec61Sdh155122 ASSERT(ss != NULL); 210f4b3ec61Sdh155122 2117c478bd9Sstevel@tonic-gate /* 2127c478bd9Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces. 2137c478bd9Sstevel@tonic-gate */ 214f4b3ec61Sdh155122 for (i = 0; i < ss->ss_sadcnt; i++) 215f4b3ec61Sdh155122 if (ss->ss_saddev[i].sa_qp == NULL) 2167c478bd9Sstevel@tonic-gate break; 217f4b3ec61Sdh155122 if (i >= ss->ss_sadcnt) { /* no such device */ 218f4b3ec61Sdh155122 netstack_rele(ss->ss_netstack); 2197c478bd9Sstevel@tonic-gate return (ENXIO); 220f4b3ec61Sdh155122 } 2217c478bd9Sstevel@tonic-gate switch (getminor(*devp)) { 2227c478bd9Sstevel@tonic-gate case USRMIN: /* mere mortal */ 223f4b3ec61Sdh155122 ss->ss_saddev[i].sa_flags = 0; 2247c478bd9Sstevel@tonic-gate break; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate case ADMMIN: /* privileged user */ 227f4b3ec61Sdh155122 ss->ss_saddev[i].sa_flags = SADPRIV; 2287c478bd9Sstevel@tonic-gate break; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate default: 231f4b3ec61Sdh155122 netstack_rele(ss->ss_netstack); 2327c478bd9Sstevel@tonic-gate return (EINVAL); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 235f4b3ec61Sdh155122 ss->ss_saddev[i].sa_qp = qp; 236f4b3ec61Sdh155122 ss->ss_saddev[i].sa_ss = ss; 237f4b3ec61Sdh155122 qp->q_ptr = (caddr_t)&ss->ss_saddev[i]; 238f4b3ec61Sdh155122 WR(qp)->q_ptr = (caddr_t)&ss->ss_saddev[i]; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate /* 2417c478bd9Sstevel@tonic-gate * NOTE: should the ADMMIN or USRMIN minors change 2427c478bd9Sstevel@tonic-gate * then so should the offset of 2 below 2437c478bd9Sstevel@tonic-gate * Both USRMIN and ADMMIN are clone interfaces and 2447c478bd9Sstevel@tonic-gate * therefore their minor numbers (0 and 1) are reserved. 2457c478bd9Sstevel@tonic-gate */ 2467c478bd9Sstevel@tonic-gate *devp = makedevice(getemajor(*devp), i + 2); 2477c478bd9Sstevel@tonic-gate qprocson(qp); 2487c478bd9Sstevel@tonic-gate return (0); 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate * sadclose() - 2537c478bd9Sstevel@tonic-gate * Clean up the data structures. 2547c478bd9Sstevel@tonic-gate */ 2557c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2567c478bd9Sstevel@tonic-gate static int 2577c478bd9Sstevel@tonic-gate sadclose( 2587c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to read queue */ 2597c478bd9Sstevel@tonic-gate int flag, /* file open flags */ 2607c478bd9Sstevel@tonic-gate cred_t *credp) /* user credentials */ 2617c478bd9Sstevel@tonic-gate { 2627c478bd9Sstevel@tonic-gate struct saddev *sadp; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate qprocsoff(qp); 2657c478bd9Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 2667c478bd9Sstevel@tonic-gate sadp->sa_qp = NULL; 2677c478bd9Sstevel@tonic-gate sadp->sa_addr = NULL; 268f4b3ec61Sdh155122 netstack_rele(sadp->sa_ss->ss_netstack); 269f4b3ec61Sdh155122 sadp->sa_ss = NULL; 2707c478bd9Sstevel@tonic-gate qp->q_ptr = NULL; 2717c478bd9Sstevel@tonic-gate WR(qp)->q_ptr = NULL; 2727c478bd9Sstevel@tonic-gate return (0); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * sadwput() - 2777c478bd9Sstevel@tonic-gate * Write side put procedure. 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate static int 2807c478bd9Sstevel@tonic-gate sadwput( 2817c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 2827c478bd9Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 2837c478bd9Sstevel@tonic-gate { 2847c478bd9Sstevel@tonic-gate struct iocblk *iocp; 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 2877c478bd9Sstevel@tonic-gate case M_FLUSH: 2887c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 2897c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 2907c478bd9Sstevel@tonic-gate qreply(qp, mp); 2917c478bd9Sstevel@tonic-gate } else 2927c478bd9Sstevel@tonic-gate freemsg(mp); 2937c478bd9Sstevel@tonic-gate break; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate case M_IOCTL: 2967c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 2977c478bd9Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 2987c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 2997c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 3007c478bd9Sstevel@tonic-gate apush_ioctl(qp, mp); 3017c478bd9Sstevel@tonic-gate break; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate case SAD_VML: 3047c478bd9Sstevel@tonic-gate vml_ioctl(qp, mp); 3057c478bd9Sstevel@tonic-gate break; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate default: 3087c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3097c478bd9Sstevel@tonic-gate break; 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate break; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate case M_IOCDATA: 3147c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3157c478bd9Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 3167c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 3177c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 3187c478bd9Sstevel@tonic-gate apush_iocdata(qp, mp); 3197c478bd9Sstevel@tonic-gate break; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate case SAD_VML: 3227c478bd9Sstevel@tonic-gate vml_iocdata(qp, mp); 3237c478bd9Sstevel@tonic-gate break; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate default: 3267c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 3277c478bd9Sstevel@tonic-gate "sadwput: invalid ioc_cmd in case M_IOCDATA: %d", 3287c478bd9Sstevel@tonic-gate iocp->ioc_cmd); 3297c478bd9Sstevel@tonic-gate freemsg(mp); 3307c478bd9Sstevel@tonic-gate break; 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate break; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate default: 3357c478bd9Sstevel@tonic-gate freemsg(mp); 3367c478bd9Sstevel@tonic-gate break; 3377c478bd9Sstevel@tonic-gate } /* switch (db_type) */ 3387c478bd9Sstevel@tonic-gate return (0); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * apush_ioctl() - 3437c478bd9Sstevel@tonic-gate * Handle the M_IOCTL messages associated with 3447c478bd9Sstevel@tonic-gate * the autopush feature. 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate static void 3477c478bd9Sstevel@tonic-gate apush_ioctl( 3487c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 3497c478bd9Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 3507c478bd9Sstevel@tonic-gate { 3517c478bd9Sstevel@tonic-gate struct iocblk *iocp; 3527c478bd9Sstevel@tonic-gate struct saddev *sadp; 3537c478bd9Sstevel@tonic-gate uint_t size; 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3567c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 3577c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3587c478bd9Sstevel@tonic-gate return; 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) > AP_VERSION) { 3617c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3627c478bd9Sstevel@tonic-gate return; 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 3667c478bd9Sstevel@tonic-gate switch (SAD_CMD(iocp->ioc_cmd)) { 3677c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_SAP): 3687c478bd9Sstevel@tonic-gate if (!(sadp->sa_flags & SADPRIV)) { 3697c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EPERM); 3707c478bd9Sstevel@tonic-gate break; 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate /* FALLTHRU */ 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 3757c478bd9Sstevel@tonic-gate sadp->sa_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 3767c478bd9Sstevel@tonic-gate if (SAD_VER(iocp->ioc_cmd) == 1) 3777c478bd9Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 3787c478bd9Sstevel@tonic-gate else 3797c478bd9Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 3807c478bd9Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, size, NULL); 3817c478bd9Sstevel@tonic-gate qreply(qp, mp); 3827c478bd9Sstevel@tonic-gate break; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate default: 3857c478bd9Sstevel@tonic-gate ASSERT(0); 3867c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 3877c478bd9Sstevel@tonic-gate break; 3887c478bd9Sstevel@tonic-gate } /* switch (ioc_cmd) */ 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * apush_iocdata() - 3937c478bd9Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 3947c478bd9Sstevel@tonic-gate * the autopush feature. 3957c478bd9Sstevel@tonic-gate */ 3967c478bd9Sstevel@tonic-gate static void 3977c478bd9Sstevel@tonic-gate apush_iocdata( 3987c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 3997c478bd9Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 4007c478bd9Sstevel@tonic-gate { 4017c478bd9Sstevel@tonic-gate int i, ret; 4027c478bd9Sstevel@tonic-gate struct copyresp *csp; 4034121995cSedp struct strapush *sap = NULL; 4041110f384Sedp struct autopush *ap, *ap_tmp; 4057c478bd9Sstevel@tonic-gate struct saddev *sadp; 4067c478bd9Sstevel@tonic-gate uint_t size; 4071110f384Sedp dev_t dev; 408f4b3ec61Sdh155122 str_stack_t *ss; 409f4b3ec61Sdh155122 410f4b3ec61Sdh155122 sadp = (struct saddev *)qp->q_ptr; 411f4b3ec61Sdh155122 ss = sadp->sa_ss; 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 4147c478bd9Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 4157c478bd9Sstevel@tonic-gate freemsg(mp); 4167c478bd9Sstevel@tonic-gate return; 4177c478bd9Sstevel@tonic-gate } 4181110f384Sedp if (mp->b_cont) { 4197c478bd9Sstevel@tonic-gate /* 4204121995cSedp * sap needed only if mp->b_cont is set. figure out the 4214121995cSedp * size of the expected sap structure and make sure 4224121995cSedp * enough data was supplied. 4237c478bd9Sstevel@tonic-gate */ 4244121995cSedp if (SAD_VER(csp->cp_cmd) == 1) 4254121995cSedp size = STRAPUSH_V1_LEN; 4264121995cSedp else 4274121995cSedp size = STRAPUSH_V0_LEN; 4284121995cSedp if (MBLKL(mp->b_cont) < size) { 4294121995cSedp miocnak(qp, mp, 0, EINVAL); 4307c478bd9Sstevel@tonic-gate return; 4317c478bd9Sstevel@tonic-gate } 4321110f384Sedp sap = (struct strapush *)mp->b_cont->b_rptr; 4331110f384Sedp dev = makedevice(sap->sap_major, sap->sap_minor); 4347c478bd9Sstevel@tonic-gate } 4351110f384Sedp switch (SAD_CMD(csp->cp_cmd)) { 4361110f384Sedp case SAD_CMD(SAD_SAP): 4377c478bd9Sstevel@tonic-gate 4381110f384Sedp /* currently we only support one SAD_SAP command */ 4391110f384Sedp if (((long)csp->cp_private) != GETSTRUCT) { 4407c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 4417c478bd9Sstevel@tonic-gate "apush_iocdata: cp_private bad in SAD_SAP: %p", 4427c478bd9Sstevel@tonic-gate (void *)csp->cp_private); 4431110f384Sedp miocnak(qp, mp, 0, EINVAL); 4441110f384Sedp return; 4451110f384Sedp } 4461110f384Sedp 4471110f384Sedp switch (sap->sap_cmd) { 4481110f384Sedp default: 4491110f384Sedp miocnak(qp, mp, 0, EINVAL); 4501110f384Sedp return; 4511110f384Sedp case SAP_ONE: 4521110f384Sedp case SAP_RANGE: 4531110f384Sedp case SAP_ALL: 4541110f384Sedp /* allocate and initialize a new config */ 4551110f384Sedp ap = sad_ap_alloc(); 4561110f384Sedp ap->ap_common = sap->sap_common; 4571110f384Sedp if (SAD_VER(csp->cp_cmd) > 0) 4581110f384Sedp ap->ap_anchor = sap->sap_anchor; 4591110f384Sedp for (i = 0; i < MIN(sap->sap_npush, MAXAPUSH); i++) 4601110f384Sedp (void) strncpy(ap->ap_list[i], 4611110f384Sedp sap->sap_list[i], FMNAMESZ); 4621110f384Sedp 4631110f384Sedp /* sanity check the request */ 4641110f384Sedp if (((ret = sad_ap_verify(ap)) != 0) || 4651110f384Sedp ((ret = valid_major(ap->ap_major)) != 0)) { 466f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 4671110f384Sedp miocnak(qp, mp, 0, ret); 4681110f384Sedp return; 4691110f384Sedp } 4701110f384Sedp 4711110f384Sedp /* check for overlapping configs */ 472f4b3ec61Sdh155122 mutex_enter(&ss->ss_sad_lock); 473f4b3ec61Sdh155122 ap_tmp = sad_ap_find(&ap->ap_common, ss); 474f4b3ec61Sdh155122 if (ap_tmp != NULL) { 4751110f384Sedp /* already configured */ 476f4b3ec61Sdh155122 mutex_exit(&ss->ss_sad_lock); 477f4b3ec61Sdh155122 sad_ap_rele(ap_tmp, ss); 478f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 4791110f384Sedp miocnak(qp, mp, 0, EEXIST); 4801110f384Sedp return; 4811110f384Sedp } 4821110f384Sedp 4831110f384Sedp /* add the new config to our hash */ 484f4b3ec61Sdh155122 sad_ap_insert(ap, ss); 485f4b3ec61Sdh155122 mutex_exit(&ss->ss_sad_lock); 4861110f384Sedp miocack(qp, mp, 0, 0); 4871110f384Sedp return; 4881110f384Sedp 4891110f384Sedp case SAP_CLEAR: 4901110f384Sedp /* sanity check the request */ 4911110f384Sedp if (ret = valid_major(sap->sap_major)) { 4921110f384Sedp miocnak(qp, mp, 0, ret); 4931110f384Sedp return; 4941110f384Sedp } 4951110f384Sedp 4961110f384Sedp /* search for a matching config */ 497f4b3ec61Sdh155122 if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { 4981110f384Sedp /* no config found */ 4991110f384Sedp miocnak(qp, mp, 0, ENODEV); 5001110f384Sedp return; 5011110f384Sedp } 5021110f384Sedp 5031110f384Sedp /* 5041110f384Sedp * If we matched a SAP_RANGE config 5051110f384Sedp * the minor passed in must match the 5061110f384Sedp * beginning of the range exactly. 5071110f384Sedp */ 5081110f384Sedp if ((ap->ap_type == SAP_RANGE) && 5091110f384Sedp (ap->ap_minor != sap->sap_minor)) { 510f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 5111110f384Sedp miocnak(qp, mp, 0, ERANGE); 5121110f384Sedp return; 5131110f384Sedp } 5141110f384Sedp 5151110f384Sedp /* 5161110f384Sedp * If we matched a SAP_ALL config 5171110f384Sedp * the minor passed in must be 0. 5181110f384Sedp */ 5191110f384Sedp if ((ap->ap_type == SAP_ALL) && 5201110f384Sedp (sap->sap_minor != 0)) { 521f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 5221110f384Sedp miocnak(qp, mp, 0, EINVAL); 5231110f384Sedp return; 5241110f384Sedp } 5251110f384Sedp 5261110f384Sedp /* 5271110f384Sedp * make sure someone else hasn't already 5281110f384Sedp * removed this config from the hash. 5291110f384Sedp */ 530f4b3ec61Sdh155122 mutex_enter(&ss->ss_sad_lock); 531f4b3ec61Sdh155122 ap_tmp = sad_ap_find(&ap->ap_common, ss); 5321110f384Sedp if (ap_tmp != ap) { 533f4b3ec61Sdh155122 mutex_exit(&ss->ss_sad_lock); 534f4b3ec61Sdh155122 sad_ap_rele(ap_tmp, ss); 535f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 5361110f384Sedp miocnak(qp, mp, 0, ENODEV); 5371110f384Sedp return; 538f4b3ec61Sdh155122 } 5391110f384Sedp 5401110f384Sedp /* remove the config from the hash and return */ 541f4b3ec61Sdh155122 sad_ap_remove(ap, ss); 542f4b3ec61Sdh155122 mutex_exit(&ss->ss_sad_lock); 5431110f384Sedp 5441110f384Sedp /* 5451110f384Sedp * Release thrice, once for sad_ap_find_by_dev(), 5461110f384Sedp * once for sad_ap_find(), and once to free. 5471110f384Sedp */ 548f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 549f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 550f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 5511110f384Sedp miocack(qp, mp, 0, 0); 5521110f384Sedp return; 5531110f384Sedp } /* switch (sap_cmd) */ 5541110f384Sedp /*NOTREACHED*/ 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate case SAD_CMD(SAD_GAP): 5577c478bd9Sstevel@tonic-gate switch ((long)csp->cp_private) { 5587c478bd9Sstevel@tonic-gate 5591110f384Sedp case GETSTRUCT: 5601110f384Sedp /* sanity check the request */ 5617c478bd9Sstevel@tonic-gate if (ret = valid_major(sap->sap_major)) { 5627c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, ret); 5631110f384Sedp return; 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate 5661110f384Sedp /* search for a matching config */ 567f4b3ec61Sdh155122 if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { 5681110f384Sedp /* no config found */ 5697c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, ENODEV); 5701110f384Sedp return; 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 5731110f384Sedp /* copy out the contents of the config */ 5747c478bd9Sstevel@tonic-gate sap->sap_common = ap->ap_common; 5757c478bd9Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) > 0) 5767c478bd9Sstevel@tonic-gate sap->sap_anchor = ap->ap_anchor; 5777c478bd9Sstevel@tonic-gate for (i = 0; i < ap->ap_npush; i++) 5787c478bd9Sstevel@tonic-gate (void) strcpy(sap->sap_list[i], ap->ap_list[i]); 5797c478bd9Sstevel@tonic-gate for (; i < MAXAPUSH; i++) 5807c478bd9Sstevel@tonic-gate bzero(sap->sap_list[i], FMNAMESZ + 1); 5817c478bd9Sstevel@tonic-gate 5821110f384Sedp /* release our hold on the config */ 583f4b3ec61Sdh155122 sad_ap_rele(ap, ss); 5841110f384Sedp 5851110f384Sedp /* copyout the results */ 5867c478bd9Sstevel@tonic-gate if (SAD_VER(csp->cp_cmd) == 1) 5877c478bd9Sstevel@tonic-gate size = STRAPUSH_V1_LEN; 5887c478bd9Sstevel@tonic-gate else 5897c478bd9Sstevel@tonic-gate size = STRAPUSH_V0_LEN; 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate mcopyout(mp, (void *)GETRESULT, size, sadp->sa_addr, 5927c478bd9Sstevel@tonic-gate NULL); 5937c478bd9Sstevel@tonic-gate qreply(qp, mp); 5941110f384Sedp return; 5957c478bd9Sstevel@tonic-gate case GETRESULT: 5967c478bd9Sstevel@tonic-gate miocack(qp, mp, 0, 0); 5971110f384Sedp return; 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate default: 6007c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 6017c478bd9Sstevel@tonic-gate "apush_iocdata: cp_private bad case SAD_GAP: %p", 6027c478bd9Sstevel@tonic-gate (void *)csp->cp_private); 6037c478bd9Sstevel@tonic-gate freemsg(mp); 6041110f384Sedp return; 6057c478bd9Sstevel@tonic-gate } /* switch (cp_private) */ 6061110f384Sedp /*NOTREACHED*/ 6077c478bd9Sstevel@tonic-gate default: /* can't happen */ 6087c478bd9Sstevel@tonic-gate ASSERT(0); 6097c478bd9Sstevel@tonic-gate freemsg(mp); 6107c478bd9Sstevel@tonic-gate return; 6111110f384Sedp } /* switch (cp_cmd) */ 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate /* 6157c478bd9Sstevel@tonic-gate * vml_ioctl() - 6167c478bd9Sstevel@tonic-gate * Handle the M_IOCTL message associated with a request 6177c478bd9Sstevel@tonic-gate * to validate a module list. 6187c478bd9Sstevel@tonic-gate */ 6197c478bd9Sstevel@tonic-gate static void 6207c478bd9Sstevel@tonic-gate vml_ioctl( 6217c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 6227c478bd9Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 6237c478bd9Sstevel@tonic-gate { 6247c478bd9Sstevel@tonic-gate struct iocblk *iocp; 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 6277c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 6287c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 6297c478bd9Sstevel@tonic-gate return; 6307c478bd9Sstevel@tonic-gate } 63164248fb8Sethindra ASSERT(SAD_CMD(iocp->ioc_cmd) == SAD_VML); 6327c478bd9Sstevel@tonic-gate mcopyin(mp, (void *)GETSTRUCT, 6337c478bd9Sstevel@tonic-gate SIZEOF_STRUCT(str_list, iocp->ioc_flag), NULL); 6347c478bd9Sstevel@tonic-gate qreply(qp, mp); 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate /* 6387c478bd9Sstevel@tonic-gate * vml_iocdata() - 6397c478bd9Sstevel@tonic-gate * Handle the M_IOCDATA messages associated with 6407c478bd9Sstevel@tonic-gate * a request to validate a module list. 6417c478bd9Sstevel@tonic-gate */ 6427c478bd9Sstevel@tonic-gate static void 6437c478bd9Sstevel@tonic-gate vml_iocdata( 6447c478bd9Sstevel@tonic-gate queue_t *qp, /* pointer to write queue */ 6457c478bd9Sstevel@tonic-gate mblk_t *mp) /* message pointer */ 6467c478bd9Sstevel@tonic-gate { 6477c478bd9Sstevel@tonic-gate long i; 6487c478bd9Sstevel@tonic-gate int nmods; 6497c478bd9Sstevel@tonic-gate struct copyresp *csp; 6507c478bd9Sstevel@tonic-gate struct str_mlist *lp; 6517c478bd9Sstevel@tonic-gate STRUCT_HANDLE(str_list, slp); 6527c478bd9Sstevel@tonic-gate struct saddev *sadp; 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 6557c478bd9Sstevel@tonic-gate if (csp->cp_rval) { /* if there was an error */ 6567c478bd9Sstevel@tonic-gate freemsg(mp); 6577c478bd9Sstevel@tonic-gate return; 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate 66064248fb8Sethindra ASSERT(SAD_CMD(csp->cp_cmd) == SAD_VML); 6617c478bd9Sstevel@tonic-gate sadp = (struct saddev *)qp->q_ptr; 6627c478bd9Sstevel@tonic-gate switch ((long)csp->cp_private) { 6637c478bd9Sstevel@tonic-gate case GETSTRUCT: 6647c478bd9Sstevel@tonic-gate STRUCT_SET_HANDLE(slp, csp->cp_flag, 6657c478bd9Sstevel@tonic-gate (struct str_list *)mp->b_cont->b_rptr); 6667c478bd9Sstevel@tonic-gate nmods = STRUCT_FGET(slp, sl_nmods); 6677c478bd9Sstevel@tonic-gate if (nmods <= 0) { 6687c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 6697c478bd9Sstevel@tonic-gate break; 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate sadp->sa_addr = (caddr_t)(uintptr_t)nmods; 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate mcopyin(mp, (void *)GETLIST, nmods * sizeof (struct str_mlist), 6747c478bd9Sstevel@tonic-gate STRUCT_FGETP(slp, sl_modlist)); 6757c478bd9Sstevel@tonic-gate qreply(qp, mp); 6767c478bd9Sstevel@tonic-gate break; 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate case GETLIST: 6797c478bd9Sstevel@tonic-gate lp = (struct str_mlist *)mp->b_cont->b_rptr; 6807c478bd9Sstevel@tonic-gate for (i = 0; i < (long)sadp->sa_addr; i++, lp++) { 6817c478bd9Sstevel@tonic-gate lp->l_name[FMNAMESZ] = '\0'; 6827c478bd9Sstevel@tonic-gate if (fmodsw_find(lp->l_name, FMODSW_LOAD) == NULL) { 6837c478bd9Sstevel@tonic-gate miocack(qp, mp, 0, 1); 6847c478bd9Sstevel@tonic-gate return; 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate miocack(qp, mp, 0, 0); 6887c478bd9Sstevel@tonic-gate break; 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate default: 6917c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "vml_iocdata: invalid cp_private value: %p", 6927c478bd9Sstevel@tonic-gate (void *)csp->cp_private); 6937c478bd9Sstevel@tonic-gate freemsg(mp); 6947c478bd9Sstevel@tonic-gate break; 6957c478bd9Sstevel@tonic-gate } /* switch (cp_private) */ 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate /* 6997c478bd9Sstevel@tonic-gate * Validate a major number and also verify if 7007c478bd9Sstevel@tonic-gate * it is a STREAMS device. 7017c478bd9Sstevel@tonic-gate * Return values: 0 if a valid STREAMS dev 7027c478bd9Sstevel@tonic-gate * error code otherwise 7037c478bd9Sstevel@tonic-gate */ 7047c478bd9Sstevel@tonic-gate static int 7057c478bd9Sstevel@tonic-gate valid_major(major_t major) 7067c478bd9Sstevel@tonic-gate { 7077c478bd9Sstevel@tonic-gate int ret = 0; 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate if (etoimajor(major) == -1) 7107c478bd9Sstevel@tonic-gate return (EINVAL); 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate /* 7137c478bd9Sstevel@tonic-gate * attempt to load the driver 'major' and verify that 7147c478bd9Sstevel@tonic-gate * it is a STREAMS driver. 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate if (ddi_hold_driver(major) == NULL) 7177c478bd9Sstevel@tonic-gate return (EINVAL); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate if (!STREAMSTAB(major)) 7207c478bd9Sstevel@tonic-gate ret = ENOSTR; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate ddi_rele_driver(major); 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate return (ret); 7257c478bd9Sstevel@tonic-gate } 726