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 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 /* 40 * Kernel TLI-like function to initialize a transport 41 * endpoint using the protocol specified. 42 * 43 * Returns: 44 * 0 on success and "tiptr" is set to a valid transport pointer, 45 * else a positive error code. 46 */ 47 48 #include <sys/param.h> 49 #include <sys/types.h> 50 #include <sys/proc.h> 51 #include <sys/file.h> 52 #include <sys/user.h> 53 #include <sys/vnode.h> 54 #include <sys/errno.h> 55 #include <sys/stream.h> 56 #include <sys/ioctl.h> 57 #include <sys/stropts.h> 58 #include <sys/strsubr.h> 59 #include <sys/tihdr.h> 60 #include <sys/timod.h> 61 #include <sys/tiuser.h> 62 #include <sys/t_kuser.h> 63 #include <sys/kmem.h> 64 #include <sys/cmn_err.h> 65 66 static t_scalar_t _t_setsize(t_scalar_t); 67 68 int 69 t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr) 70 { 71 int madefp = 0; 72 struct T_info_ack inforeq; 73 int retval; 74 vnode_t *vp; 75 struct strioctl strioc; 76 int error; 77 TIUSER *ntiptr; 78 int rtries = 0; 79 80 /* 81 * Special case for install: miniroot needs to be able to access files 82 * via NFS as though it were always in the global zone. 83 */ 84 if (nfs_global_client_only != 0) 85 cr = kcred; 86 87 KTLILOG(2, "t_kopen: fp %x, ", fp); 88 KTLILOG(2, "rdev %x, ", rdev); 89 KTLILOG(2, "flags %x\n", flags); 90 91 *tiptr = NULL; 92 error = 0; 93 retval = 0; 94 if (fp == NULL) { 95 if (rdev == NODEV) { 96 KTLILOG(1, "t_kopen: null device\n", 0); 97 return (EINVAL); 98 } 99 100 /* 101 * allocate a file pointer, but 102 * no file descripter. 103 */ 104 if ((error = falloc(NULL, flags, &fp, NULL)) != 0) { 105 KTLILOG(1, "t_kopen: falloc: %d\n", error); 106 return (error); 107 } 108 109 /* Install proper cred in file */ 110 if (cr != fp->f_cred) { 111 crhold(cr); 112 crfree(fp->f_cred); 113 fp->f_cred = cr; 114 } 115 116 vp = makespecvp(rdev, VCHR); 117 118 /* 119 * this will call the streams open for us. 120 * Want to retry if error is EAGAIN, the streams open routine 121 * might fail due to temporarely out of memory. 122 */ 123 do { 124 if ((error = VOP_OPEN(&vp, flags, cr, NULL)) 125 == EAGAIN) { 126 (void) delay(hz); 127 } 128 } while (error == EAGAIN && ++rtries < 5); 129 130 if (error) { 131 KTLILOG(1, "t_kopen: VOP_OPEN: %d\n", error); 132 unfalloc(fp); 133 VN_RELE(vp); 134 return (error); 135 } 136 /* 137 * fp is completely initialized so drop the write lock. 138 * I actually don't need any locking on fp in here since 139 * there is no fd pointing at it. However, since I could 140 * call closef if there is an error and closef requires 141 * the fp read locked, I will acquire the read lock here 142 * and make sure I release it before I leave this routine. 143 */ 144 fp->f_vnode = vp; 145 mutex_exit(&fp->f_tlock); 146 147 madefp = 1; 148 } else { 149 vp = fp->f_vnode; 150 } 151 152 if (vp->v_stream == NULL) { 153 if (madefp) 154 (void) closef(fp); 155 KTLILOG(1, "t_kopen: not a streams device\n", 0); 156 return (ENOSTR); 157 } 158 159 /* 160 * allocate a new transport structure 161 */ 162 ntiptr = kmem_alloc(TIUSERSZ, KM_SLEEP); 163 ntiptr->fp = fp; 164 ntiptr->flags = madefp ? MADE_FP : 0; 165 166 KTLILOG(2, "t_kopen: vp %x, ", vp); 167 KTLILOG(2, "stp %x\n", vp->v_stream); 168 169 /* 170 * see if TIMOD is already pushed 171 */ 172 error = strioctl(vp, I_FIND, (intptr_t)"timod", 0, K_TO_K, cr, &retval); 173 if (error) { 174 kmem_free(ntiptr, TIUSERSZ); 175 if (madefp) 176 (void) closef(fp); 177 KTLILOG(1, "t_kopen: strioctl(I_FIND, timod): %d\n", error); 178 return (error); 179 } 180 181 if (retval == 0) { 182 tryagain: 183 error = strioctl(vp, I_PUSH, (intptr_t)"timod", 0, K_TO_K, cr, 184 &retval); 185 if (error) { 186 switch (error) { 187 case ENOSPC: 188 case EAGAIN: 189 case ENOSR: 190 /* 191 * This probably means the master file 192 * should be tuned. 193 */ 194 cmn_err(CE_WARN, 195 "t_kopen: I_PUSH of timod failed, error %d\n", 196 error); 197 (void) delay(hz); 198 error = 0; 199 goto tryagain; 200 201 default: 202 kmem_free(ntiptr, TIUSERSZ); 203 if (madefp) 204 (void) closef(fp); 205 KTLILOG(1, "t_kopen: I_PUSH (timod): %d", 206 error); 207 return (error); 208 } 209 } 210 } 211 212 inforeq.PRIM_type = T_INFO_REQ; 213 strioc.ic_cmd = TI_GETINFO; 214 strioc.ic_timout = 0; 215 strioc.ic_dp = (char *)&inforeq; 216 strioc.ic_len = (int)sizeof (struct T_info_req); 217 218 error = strdoioctl(vp->v_stream, &strioc, FNATIVE, K_TO_K, cr, &retval); 219 if (error) { 220 kmem_free(ntiptr, TIUSERSZ); 221 if (madefp) 222 (void) closef(fp); 223 KTLILOG(1, "t_kopen: strdoioctl(T_INFO_REQ): %d\n", error); 224 return (error); 225 } 226 227 if (retval) { 228 if ((retval & 0xff) == TSYSERR) 229 error = (retval >> 8) & 0xff; 230 else 231 error = t_tlitosyserr(retval & 0xff); 232 kmem_free(ntiptr, TIUSERSZ); 233 if (madefp) 234 (void) closef(fp); 235 KTLILOG(1, "t_kopen: strdoioctl(T_INFO_REQ): retval: 0x%x\n", 236 retval); 237 return (error); 238 } 239 240 if (strioc.ic_len != sizeof (struct T_info_ack)) { 241 kmem_free(ntiptr, TIUSERSZ); 242 if (madefp) 243 (void) closef(fp); 244 KTLILOG(1, 245 "t_kopen: strioc.ic_len != sizeof (struct T_info_ack): %d\n", 246 strioc.ic_len); 247 return (EPROTO); 248 } 249 250 ntiptr->tp_info.addr = _t_setsize(inforeq.ADDR_size); 251 ntiptr->tp_info.options = _t_setsize(inforeq.OPT_size); 252 ntiptr->tp_info.tsdu = _t_setsize(inforeq.TSDU_size); 253 ntiptr->tp_info.etsdu = _t_setsize(inforeq.ETSDU_size); 254 ntiptr->tp_info.connect = _t_setsize(inforeq.CDATA_size); 255 ntiptr->tp_info.discon = _t_setsize(inforeq.DDATA_size); 256 ntiptr->tp_info.servtype = inforeq.SERV_type; 257 258 *tiptr = ntiptr; 259 260 return (0); 261 } 262 263 #define DEFSIZE 128 264 265 static t_scalar_t 266 _t_setsize(t_scalar_t infosize) 267 { 268 switch (infosize) { 269 case -1: 270 return (DEFSIZE); 271 case -2: 272 return (0); 273 default: 274 return (infosize); 275 } 276 } 277