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