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 (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 /* 26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 #include "mt.h" 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <stropts.h> 34 #include <sys/stream.h> 35 #define _SUN_TPI_VERSION 2 36 #include <sys/tihdr.h> 37 #include <sys/timod.h> 38 #include <xti.h> 39 #include <stdio.h> 40 #include <errno.h> 41 #include <ucred.h> 42 #include <signal.h> 43 #include "tx.h" 44 45 /* 46 * Function protoypes 47 */ 48 static int _alloc_buf(struct netbuf *buf, t_scalar_t n, int fields, 49 int api_semantics, boolean_t option); 50 51 char * 52 _tx_alloc(int fd, int struct_type, int fields, int api_semantics) 53 { 54 struct strioctl strioc; 55 struct T_info_ack info; 56 union structptrs { 57 char *caddr; 58 struct t_bind *bind; 59 struct t_call *call; 60 struct t_discon *dis; 61 struct t_optmgmt *opt; 62 struct t_unitdata *udata; 63 struct t_uderr *uderr; 64 struct t_info *info; 65 } p; 66 unsigned int dsize; 67 struct _ti_user *tiptr; 68 int retval, sv_errno; 69 t_scalar_t optsize; 70 71 if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL) 72 return (NULL); 73 sig_mutex_lock(&tiptr->ti_lock); 74 75 /* 76 * Get size info for T_ADDR, T_OPT, and T_UDATA fields 77 */ 78 info.PRIM_type = T_INFO_REQ; 79 strioc.ic_cmd = TI_GETINFO; 80 strioc.ic_timout = -1; 81 strioc.ic_len = (int)sizeof (struct T_info_req); 82 strioc.ic_dp = (char *)&info; 83 do { 84 retval = ioctl(fd, I_STR, &strioc); 85 } while (retval < 0 && errno == EINTR); 86 87 if (retval < 0) { 88 sv_errno = errno; 89 sig_mutex_unlock(&tiptr->ti_lock); 90 t_errno = TSYSERR; 91 errno = sv_errno; 92 return (NULL); 93 } 94 95 if (strioc.ic_len != (int)sizeof (struct T_info_ack)) { 96 t_errno = TSYSERR; 97 sig_mutex_unlock(&tiptr->ti_lock); 98 errno = EIO; 99 return (NULL); 100 } 101 102 103 /* 104 * Malloc appropriate structure and the specified 105 * fields within each structure. Initialize the 106 * 'buf' and 'maxlen' fields of each. 107 */ 108 switch (struct_type) { 109 110 case T_BIND: 111 if ((p.bind = calloc(1, sizeof (struct t_bind))) == NULL) 112 goto errout; 113 if (fields & T_ADDR) { 114 if (_alloc_buf(&p.bind->addr, 115 info.ADDR_size, 116 fields, api_semantics, B_FALSE) < 0) 117 goto errout; 118 } 119 sig_mutex_unlock(&tiptr->ti_lock); 120 return ((char *)p.bind); 121 122 case T_CALL: 123 if ((p.call = calloc(1, sizeof (struct t_call))) == NULL) 124 goto errout; 125 if (fields & T_ADDR) { 126 if (_alloc_buf(&p.call->addr, 127 info.ADDR_size, 128 fields, api_semantics, B_FALSE) < 0) 129 goto errout; 130 } 131 if (fields & T_OPT) { 132 if (info.OPT_size >= 0 && _T_IS_XTI(api_semantics)) 133 /* compensate for XTI level options */ 134 optsize = info.OPT_size + 135 TX_XTI_LEVEL_MAX_OPTBUF; 136 else 137 optsize = info.OPT_size; 138 if (_alloc_buf(&p.call->opt, optsize, 139 fields, api_semantics, B_TRUE) < 0) 140 goto errout; 141 } 142 if (fields & T_UDATA) { 143 dsize = _T_MAX((int)info.CDATA_size, 144 (int)info.DDATA_size); 145 if (_alloc_buf(&p.call->udata, (t_scalar_t)dsize, 146 fields, api_semantics, B_FALSE) < 0) 147 goto errout; 148 } 149 sig_mutex_unlock(&tiptr->ti_lock); 150 return ((char *)p.call); 151 152 case T_OPTMGMT: 153 if ((p.opt = calloc(1, sizeof (struct t_optmgmt))) == NULL) 154 goto errout; 155 if (fields & T_OPT) { 156 if (info.OPT_size >= 0 && _T_IS_XTI(api_semantics)) 157 /* compensate for XTI level options */ 158 optsize = info.OPT_size + 159 TX_XTI_LEVEL_MAX_OPTBUF; 160 else 161 optsize = info.OPT_size; 162 if (_alloc_buf(&p.opt->opt, optsize, 163 fields, api_semantics, B_TRUE) < 0) 164 goto errout; 165 } 166 sig_mutex_unlock(&tiptr->ti_lock); 167 return ((char *)p.opt); 168 169 case T_DIS: 170 if ((p.dis = calloc(1, sizeof (struct t_discon))) == NULL) 171 goto errout; 172 if (fields & T_UDATA) { 173 if (_alloc_buf(&p.dis->udata, info.DDATA_size, 174 fields, api_semantics, B_FALSE) < 0) 175 goto errout; 176 } 177 sig_mutex_unlock(&tiptr->ti_lock); 178 return ((char *)p.dis); 179 180 case T_UNITDATA: 181 if ((p.udata = calloc(1, sizeof (struct t_unitdata))) == NULL) 182 goto errout; 183 if (fields & T_ADDR) { 184 if (_alloc_buf(&p.udata->addr, info.ADDR_size, 185 fields, api_semantics, B_FALSE) < 0) 186 goto errout; 187 } 188 if (fields & T_OPT) { 189 if (info.OPT_size >= 0 && _T_IS_XTI(api_semantics)) 190 /* compensate for XTI level options */ 191 optsize = info.OPT_size + 192 TX_XTI_LEVEL_MAX_OPTBUF; 193 else 194 optsize = info.OPT_size; 195 if (_alloc_buf(&p.udata->opt, optsize, 196 fields, api_semantics, B_TRUE) < 0) 197 goto errout; 198 } 199 if (fields & T_UDATA) { 200 if (_alloc_buf(&p.udata->udata, info.TSDU_size, 201 fields, api_semantics, B_FALSE) < 0) 202 goto errout; 203 } 204 sig_mutex_unlock(&tiptr->ti_lock); 205 return ((char *)p.udata); 206 207 case T_UDERROR: 208 if ((p.uderr = calloc(1, sizeof (struct t_uderr))) == NULL) 209 goto errout; 210 if (fields & T_ADDR) { 211 if (_alloc_buf(&p.uderr->addr, info.ADDR_size, 212 fields, api_semantics, B_FALSE) < 0) 213 goto errout; 214 } 215 if (fields & T_OPT) { 216 if (info.OPT_size >= 0 && _T_IS_XTI(api_semantics)) 217 /* compensate for XTI level options */ 218 optsize = info.OPT_size + 219 TX_XTI_LEVEL_MAX_OPTBUF; 220 else 221 optsize = info.OPT_size; 222 if (_alloc_buf(&p.uderr->opt, optsize, 223 fields, api_semantics, B_FALSE) < 0) 224 goto errout; 225 } 226 sig_mutex_unlock(&tiptr->ti_lock); 227 return ((char *)p.uderr); 228 229 case T_INFO: 230 if ((p.info = calloc(1, sizeof (struct t_info))) == NULL) 231 goto errout; 232 sig_mutex_unlock(&tiptr->ti_lock); 233 return ((char *)p.info); 234 235 default: 236 if (_T_IS_XTI(api_semantics)) { 237 t_errno = TNOSTRUCTYPE; 238 sig_mutex_unlock(&tiptr->ti_lock); 239 } else { /* TX_TLI_API */ 240 t_errno = TSYSERR; 241 sig_mutex_unlock(&tiptr->ti_lock); 242 errno = EINVAL; 243 } 244 return (NULL); 245 } 246 247 /* 248 * Clean up. Set t_errno to TSYSERR. 249 * If it is because memory could not be allocated 250 * then errno already should have been set to 251 * ENOMEM 252 */ 253 errout: 254 if (p.caddr) 255 (void) t_free(p.caddr, struct_type); 256 257 t_errno = TSYSERR; 258 sig_mutex_unlock(&tiptr->ti_lock); 259 return (NULL); 260 } 261 262 static int 263 _alloc_buf(struct netbuf *buf, t_scalar_t n, int fields, int api_semantics, 264 boolean_t option) 265 { 266 switch (n) { 267 case T_INFINITE /* -1 */: 268 if (_T_IS_XTI(api_semantics)) { 269 buf->buf = NULL; 270 buf->maxlen = 0; 271 if (fields != T_ALL) { 272 /* 273 * Do not return error 274 * if T_ALL is used. 275 */ 276 errno = EINVAL; 277 return (-1); 278 } 279 } else if (option) { /* TX_TLI_API */ 280 static size_t infalloc; 281 282 /* 283 * retain TLI behavior; ucred_t can vary in size, 284 * we need to make sure that we can receive one. 285 */ 286 if (infalloc == 0) { 287 size_t uc = ucred_size(); 288 if (uc < 1024/2) 289 infalloc = 1024; 290 else 291 infalloc = uc + 1024/2; 292 } 293 if ((buf->buf = calloc(1, infalloc)) == NULL) { 294 errno = ENOMEM; 295 return (-1); 296 } else 297 buf->maxlen = infalloc; 298 } else { /* TX_TLI_API */ 299 /* 300 * retain TLI behavior 301 */ 302 if ((buf->buf = calloc(1, 1024)) == NULL) { 303 errno = ENOMEM; 304 return (-1); 305 } else 306 buf->maxlen = 1024; 307 } 308 break; 309 310 case 0: 311 buf->buf = NULL; 312 buf->maxlen = 0; 313 break; 314 315 case T_INVALID /* -2 */: 316 if (_T_IS_XTI(api_semantics)) { 317 buf->buf = NULL; 318 buf->maxlen = 0; 319 if (fields != T_ALL) { 320 /* 321 * Do not return error 322 * if T_ALL is used. 323 */ 324 errno = EINVAL; 325 return (-1); 326 } 327 } else { /* TX_TLI_API */ 328 /* 329 * retain TLI behavior 330 */ 331 buf->buf = NULL; 332 buf->maxlen = 0; 333 } 334 break; 335 336 default: 337 if ((buf->buf = calloc(1, (size_t)n)) == NULL) { 338 errno = ENOMEM; 339 return (-1); 340 } else 341 buf->maxlen = n; 342 break; 343 } 344 return (0); 345 } 346