1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 22 /* All Rights Reserved */ 23 24 25 /* 26 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 31 /* 32 * Clone Driver. 33 */ 34 35 #include <sys/types.h> 36 #include <sys/param.h> 37 #include <sys/errno.h> 38 #include <sys/signal.h> 39 #include <sys/vfs.h> 40 #include <sys/vnode.h> 41 #include <sys/pcb.h> 42 #include <sys/user.h> 43 #include <sys/stropts.h> 44 #include <sys/stream.h> 45 #include <sys/errno.h> 46 #include <sys/sysinfo.h> 47 #include <sys/systm.h> 48 #include <sys/conf.h> 49 #include <sys/debug.h> 50 #include <sys/cred.h> 51 #include <sys/mkdev.h> 52 #include <sys/open.h> 53 #include <sys/strsubr.h> 54 #include <sys/ddi.h> 55 #include <sys/sunddi.h> 56 #include <sys/modctl.h> 57 #include <sys/policy.h> 58 59 int clnopen(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *crp); 60 61 static struct module_info clnm_info = { 0, "CLONE", 0, 0, 0, 0 }; 62 static struct qinit clnrinit = { NULL, NULL, clnopen, NULL, NULL, &clnm_info, 63 NULL }; 64 static struct qinit clnwinit = { NULL, NULL, NULL, NULL, NULL, &clnm_info, 65 NULL }; 66 struct streamtab clninfo = { &clnrinit, &clnwinit }; 67 68 static int cln_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 69 static int cln_attach(dev_info_t *, ddi_attach_cmd_t); 70 static dev_info_t *cln_dip; /* private copy of devinfo pointer */ 71 72 #define CLONE_CONF_FLAG (D_NEW|D_MP) 73 74 DDI_DEFINE_STREAM_OPS(clone_ops, nulldev, nulldev, cln_attach, nodev, nodev, \ 75 cln_info, CLONE_CONF_FLAG, &clninfo, ddi_quiesce_not_needed); 76 77 /* 78 * Module linkage information for the kernel. 79 */ 80 81 static struct modldrv modldrv = { 82 &mod_driverops, /* Type of module. This one is a pseudo driver */ 83 "Clone Pseudodriver 'clone'", 84 &clone_ops, /* driver ops */ 85 }; 86 87 static struct modlinkage modlinkage = { 88 MODREV_1, 89 { (void *)&modldrv, NULL } 90 }; 91 92 93 int 94 _init(void) 95 { 96 return (mod_install(&modlinkage)); 97 } 98 99 int 100 _fini(void) 101 { 102 /* 103 * Since the clone driver's reference count is unreliable, 104 * make sure we are never unloaded. 105 */ 106 return (EBUSY); 107 } 108 109 int 110 _info(struct modinfo *modinfop) 111 { 112 return (mod_info(&modlinkage, modinfop)); 113 } 114 115 /* ARGSUSED */ 116 static int 117 cln_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 118 { 119 cln_dip = devi; 120 return (DDI_SUCCESS); 121 } 122 123 /* ARGSUSED */ 124 static int 125 cln_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 126 void **result) 127 { 128 int error; 129 130 switch (infocmd) { 131 case DDI_INFO_DEVT2DEVINFO: 132 if (cln_dip == NULL) { 133 error = DDI_FAILURE; 134 } else { 135 *result = (void *)cln_dip; 136 error = DDI_SUCCESS; 137 } 138 break; 139 case DDI_INFO_DEVT2INSTANCE: 140 *result = (void *)0; 141 error = DDI_SUCCESS; 142 break; 143 default: 144 error = DDI_FAILURE; 145 } 146 return (error); 147 } 148 149 /* 150 * Clone open. Maj is the major device number of the streams 151 * device to open. Look up the device in the cdevsw[]. Attach 152 * its qinit structures to the read and write queues and call its 153 * open with the sflag set to CLONEOPEN. Swap in a new vnode with 154 * the real device number constructed from either 155 * a) for old-style drivers: 156 * maj and the minor returned by the device open, or 157 * b) for new-style drivers: 158 * the whole dev passed back as a reference parameter 159 * from the device open. 160 */ 161 int 162 clnopen(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *crp) 163 { 164 struct streamtab *str; 165 dev_t newdev; 166 int error = 0; 167 major_t maj; 168 minor_t emaj; 169 struct qinit *rinit, *winit; 170 cdevsw_impl_t *dp; 171 uint32_t qflag; 172 uint32_t sqtype; 173 perdm_t *dmp; 174 vnode_t *vp; 175 176 if (sflag) 177 return (ENXIO); 178 179 /* 180 * Get the device to open. 181 */ 182 emaj = getminor(*devp); /* minor is major for a cloned driver */ 183 maj = etoimajor(emaj); /* get internal major of cloned driver */ 184 185 if (maj >= devcnt) 186 return (ENXIO); 187 188 /* 189 * NOTE We call ddi_hold_installed_driver() here to attach 190 * all instances of the driver, since we do not know 191 * a priori which instance the Stream is associated with. 192 * 193 * For Style-2 network drivers, we know that the association 194 * happens at DL_ATTACH time. For other types of drivers, 195 * open probably requires attaching instance 0 (pseudo dip). 196 * 197 * To eliminate ddi_hold_installed_driver(), the following 198 * should happen: 199 * 200 * - GLD be modified to include gld_init(). The driver will 201 * register information for gld_open() to succeed. It will 202 * also inform framework if driver assigns instance=PPA. 203 * - ddi_hold_devi_by_instance() be modified to actively 204 * attach the instance via top-down enumeration. 205 */ 206 if (ddi_hold_installed_driver(maj) == NULL) 207 return (ENXIO); 208 209 if ((str = STREAMSTAB(maj)) == NULL) { 210 ddi_rele_driver(maj); 211 return (ENXIO); 212 } 213 214 newdev = makedevice(emaj, 0); /* create new style device number */ 215 216 /* 217 * Check for security here. For DLPI style 2 network 218 * drivers, we need to apply the default network policy. 219 * Clone is weird in that the network driver isn't loaded 220 * and attached at spec_open() time, we need to load the 221 * driver to see if it is a network driver. Hence, we 222 * check security here (after ddi_hold_installed_driver 223 * call above). 224 */ 225 vp = makespecvp(newdev, VCHR); 226 error = secpolicy_spec_open(crp, vp, flag); 227 VN_RELE(vp); 228 if (error) { 229 ddi_rele_driver(maj); 230 return (error); 231 } 232 233 /* 234 * Save so that we can restore the q on failure. 235 */ 236 rinit = rq->q_qinfo; 237 winit = WR(rq)->q_qinfo; 238 ASSERT(rq->q_syncq->sq_type == (SQ_CI|SQ_CO)); 239 ASSERT((rq->q_flag & QMT_TYPEMASK) == QMTSAFE); 240 241 dp = &devimpl[maj]; 242 ASSERT(str == dp->d_str); 243 244 qflag = dp->d_qflag; 245 sqtype = dp->d_sqtype; 246 247 /* create perdm_t if needed */ 248 if (NEED_DM(dp->d_dmp, qflag)) 249 dp->d_dmp = hold_dm(str, qflag, sqtype); 250 251 dmp = dp->d_dmp; 252 253 /* 254 * Set the syncq state what qattach started off with. This is safe 255 * since no other thread can access this queue at this point 256 * (stream open, close, push, and pop are single threaded 257 * by the framework.) 258 */ 259 leavesq(rq->q_syncq, SQ_OPENCLOSE); 260 261 /* 262 * Substitute the real qinit values for the current ones. 263 */ 264 /* setq might sleep in kmem_alloc - avoid holding locks. */ 265 setq(rq, str->st_rdinit, str->st_wrinit, dmp, qflag, sqtype, B_FALSE); 266 267 /* 268 * Open the attached module or driver. 269 * 270 * If there is an outer perimeter get exclusive access during 271 * the open procedure. 272 * Bump up the reference count on the queue. 273 */ 274 entersq(rq->q_syncq, SQ_OPENCLOSE); 275 276 /* 277 * Call the device open with the stream flag CLONEOPEN. The device 278 * will either fail this or return the device number. 279 */ 280 error = (*rq->q_qinfo->qi_qopen)(rq, &newdev, flag, CLONEOPEN, crp); 281 if (error != 0) 282 goto failed; 283 284 *devp = newdev; 285 if (getmajor(newdev) != emaj) 286 goto bad_major; 287 288 return (0); 289 290 bad_major: 291 /* 292 * Close the device 293 */ 294 (*rq->q_qinfo->qi_qclose)(rq, flag, crp); 295 296 #ifdef DEBUG 297 cmn_err(CE_NOTE, "cannot clone major number %d(%s)->%d", emaj, 298 ddi_major_to_name(emaj), getmajor(newdev)); 299 #endif 300 error = ENXIO; 301 302 failed: 303 /* 304 * open failed; pretty up to look like original 305 * queue. 306 */ 307 if (backq(WR(rq)) && backq(WR(rq))->q_next == WR(rq)) 308 qprocsoff(rq); 309 leavesq(rq->q_syncq, SQ_OPENCLOSE); 310 rq->q_next = WR(rq)->q_next = NULL; 311 ASSERT(flush_syncq(rq->q_syncq, rq) == 0); 312 ASSERT(flush_syncq(WR(rq)->q_syncq, WR(rq)) == 0); 313 rq->q_ptr = WR(rq)->q_ptr = NULL; 314 /* setq might sleep in kmem_alloc - avoid holding locks. */ 315 setq(rq, rinit, winit, NULL, QMTSAFE, SQ_CI|SQ_CO, 316 B_FALSE); 317 318 /* Restore back to what qattach will expect */ 319 entersq(rq->q_syncq, SQ_OPENCLOSE); 320 321 ddi_rele_driver(maj); 322 return (error); 323 }