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 (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 24 /* All Rights Reserved */ 25 26 /* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include "mt.h" 34 #include <sys/param.h> 35 #include <sys/types.h> 36 #include <errno.h> 37 #include <string.h> 38 #include <stdlib.h> 39 #include <stropts.h> 40 #include <sys/stream.h> 41 #define _SUN_TPI_VERSION 2 42 #include <sys/tihdr.h> 43 #include <sys/timod.h> 44 #include <xti.h> 45 #include <signal.h> 46 #include <assert.h> 47 #include "tx.h" 48 49 50 /* 51 * Snd_conn_req - send connect request message to transport provider. 52 * All signals for the caller are blocked during the call to simplify design. 53 * (This is OK for a bounded amount of time this routine is expected to 54 * execute). Also, assumes tiptr->ti_lock is held. 55 */ 56 int 57 _t_snd_conn_req( 58 struct _ti_user *tiptr, 59 const struct t_call *call, 60 struct strbuf *ctlbufp) 61 { 62 struct T_conn_req *creq; 63 int size; 64 int fd; 65 66 assert(MUTEX_HELD(&tiptr->ti_lock)); 67 fd = tiptr->ti_fd; 68 69 if (tiptr->ti_servtype == T_CLTS) { 70 t_errno = TNOTSUPPORT; 71 return (-1); 72 } 73 74 if (_t_is_event(fd, tiptr) < 0) 75 return (-1); 76 77 /* LINTED pointer cast */ 78 creq = (struct T_conn_req *)ctlbufp->buf; 79 creq->PRIM_type = T_CONN_REQ; 80 creq->DEST_length = call->addr.len; 81 creq->DEST_offset = 0; 82 creq->OPT_length = call->opt.len; 83 creq->OPT_offset = 0; 84 size = (int)sizeof (struct T_conn_req); /* size without any buffers */ 85 86 if (call->addr.len) { 87 if (_t_aligned_copy(ctlbufp, call->addr.len, size, 88 call->addr.buf, &creq->DEST_offset) < 0) { 89 /* 90 * Aligned copy will overflow buffer allocated based 91 * based on transport maximum address size. 92 * return error. 93 */ 94 t_errno = TBADADDR; 95 return (-1); 96 } 97 size = creq->DEST_offset + creq->DEST_length; 98 } 99 if (call->opt.len) { 100 if (_t_aligned_copy(ctlbufp, call->opt.len, size, 101 call->opt.buf, &creq->OPT_offset) < 0) { 102 /* 103 * Aligned copy will overflow buffer allocated based 104 * on maximum option size in transport. 105 * return error. 106 */ 107 t_errno = TBADOPT; 108 return (-1); 109 } 110 size = creq->OPT_offset + creq->OPT_length; 111 } 112 if (call->udata.len) { 113 if ((tiptr->ti_cdatasize == T_INVALID /* -2 */) || 114 ((tiptr->ti_cdatasize != T_INFINITE /* -1 */) && 115 (call->udata.len > (uint32_t)tiptr->ti_cdatasize))) { 116 /* 117 * user data not valid with connect or it 118 * exceeds the limits specified by the transport 119 * provider. 120 */ 121 t_errno = TBADDATA; 122 return (-1); 123 } 124 } 125 126 ctlbufp->len = size; 127 128 /* 129 * Assumes signals are blocked so putmsg() will not block 130 * indefinitely 131 */ 132 if (putmsg(fd, ctlbufp, 133 (struct strbuf *)(call->udata.len? &call->udata: NULL), 0) < 0) { 134 t_errno = TSYSERR; 135 return (-1); 136 } 137 138 if (_t_is_ok(fd, tiptr, T_CONN_REQ) < 0) 139 return (-1); 140 return (0); 141 } 142 143 144 145 /* 146 * Rcv_conn_con - get connection confirmation off 147 * of read queue 148 * Note: 149 * - called holding the tiptr->ti_lock 150 */ 151 int 152 _t_rcv_conn_con( 153 struct _ti_user *tiptr, 154 struct t_call *call, 155 struct strbuf *ctlbufp, 156 int api_semantics) 157 { 158 struct strbuf databuf; 159 union T_primitives *pptr; 160 int retval, fd, sv_errno; 161 int didralloc; 162 163 int flg = 0; 164 165 fd = tiptr->ti_fd; 166 167 if (tiptr->ti_servtype == T_CLTS) { 168 t_errno = TNOTSUPPORT; 169 return (-1); 170 } 171 172 /* 173 * see if there is something in look buffer 174 */ 175 if (tiptr->ti_lookcnt > 0) { 176 t_errno = TLOOK; 177 return (-1); 178 } 179 180 ctlbufp->len = 0; 181 /* 182 * Acquire databuf for use in sending/receiving data part 183 */ 184 if (_t_acquire_databuf(tiptr, &databuf, &didralloc) < 0) 185 return (-1); 186 187 /* 188 * This is a call that may block indefinitely so we drop the 189 * lock and allow signals in MT case here and reacquire it. 190 * Error case should roll back state changes done above 191 * (happens to be no state change here) 192 */ 193 sig_mutex_unlock(&tiptr->ti_lock); 194 if ((retval = getmsg(fd, ctlbufp, &databuf, &flg)) < 0) { 195 sv_errno = errno; 196 if (errno == EAGAIN) 197 t_errno = TNODATA; 198 else 199 t_errno = TSYSERR; 200 sig_mutex_lock(&tiptr->ti_lock); 201 errno = sv_errno; 202 goto err_out; 203 } 204 sig_mutex_lock(&tiptr->ti_lock); 205 206 if (databuf.len == -1) databuf.len = 0; 207 208 /* 209 * did we get entire message 210 */ 211 if (retval > 0) { 212 t_errno = TSYSERR; 213 errno = EIO; 214 goto err_out; 215 } 216 217 /* 218 * is cntl part large enough to determine message type? 219 */ 220 if (ctlbufp->len < (int)sizeof (t_scalar_t)) { 221 t_errno = TSYSERR; 222 errno = EPROTO; 223 goto err_out; 224 } 225 226 /* LINTED pointer cast */ 227 pptr = (union T_primitives *)ctlbufp->buf; 228 229 switch (pptr->type) { 230 231 case T_CONN_CON: 232 233 if ((ctlbufp->len < (int)sizeof (struct T_conn_con)) || 234 (pptr->conn_con.OPT_length != 0 && 235 (ctlbufp->len < (int)(pptr->conn_con.OPT_length + 236 pptr->conn_con.OPT_offset)))) { 237 t_errno = TSYSERR; 238 errno = EPROTO; 239 goto err_out; 240 } 241 242 if (call != NULL) { 243 /* 244 * Note: Buffer overflow is an error in XTI 245 * only if netbuf.maxlen > 0 246 */ 247 if (_T_IS_TLI(api_semantics) || call->addr.maxlen > 0) { 248 if (TLEN_GT_NLEN(pptr->conn_con.RES_length, 249 call->addr.maxlen)) { 250 t_errno = TBUFOVFLW; 251 goto err_out; 252 } 253 (void) memcpy(call->addr.buf, 254 ctlbufp->buf + pptr->conn_con.RES_offset, 255 (size_t)pptr->conn_con.RES_length); 256 call->addr.len = pptr->conn_con.RES_length; 257 } 258 if (_T_IS_TLI(api_semantics) || call->opt.maxlen > 0) { 259 if (TLEN_GT_NLEN(pptr->conn_con.OPT_length, 260 call->opt.maxlen)) { 261 t_errno = TBUFOVFLW; 262 goto err_out; 263 } 264 (void) memcpy(call->opt.buf, 265 ctlbufp->buf + pptr->conn_con.OPT_offset, 266 (size_t)pptr->conn_con.OPT_length); 267 call->opt.len = pptr->conn_con.OPT_length; 268 } 269 if (_T_IS_TLI(api_semantics) || 270 call->udata.maxlen > 0) { 271 if (databuf.len > (int)call->udata.maxlen) { 272 t_errno = TBUFOVFLW; 273 goto err_out; 274 } 275 (void) memcpy(call->udata.buf, databuf.buf, 276 (size_t)databuf.len); 277 call->udata.len = databuf.len; 278 } 279 /* 280 * since a confirmation seq number 281 * is -1 by default 282 */ 283 call->sequence = (int)-1; 284 } 285 if (didralloc) 286 free(databuf.buf); 287 else 288 tiptr->ti_rcvbuf = databuf.buf; 289 return (0); 290 291 case T_DISCON_IND: 292 293 /* 294 * if disconnect indication then append it to 295 * the "look bufffer" list. 296 * This may result in MT case for the process 297 * signal mask to be temporarily masked to 298 * ensure safe memory allocation. 299 */ 300 301 if (_t_register_lookevent(tiptr, databuf.buf, databuf.len, 302 ctlbufp->buf, ctlbufp->len) < 0) { 303 t_errno = TSYSERR; 304 errno = ENOMEM; 305 goto err_out; 306 } 307 t_errno = TLOOK; 308 goto err_out; 309 310 default: 311 break; 312 } 313 314 t_errno = TSYSERR; 315 errno = EPROTO; 316 err_out: 317 if (didralloc) 318 free(databuf.buf); 319 else 320 tiptr->ti_rcvbuf = databuf.buf; 321 return (-1); 322 } 323