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