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 32 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */ 33 34 #include "mt.h" 35 #include <rpc/trace.h> 36 #include <errno.h> 37 #include <stdlib.h> 38 #include <string.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 <syslog.h> 46 #include "tx.h" 47 48 int 49 _tx_listen(int fd, struct t_call *call, int api_semantics) 50 { 51 struct strbuf ctlbuf; 52 struct strbuf databuf; 53 int retval; 54 union T_primitives *pptr; 55 struct _ti_user *tiptr; 56 int sv_errno; 57 int didalloc, didralloc; 58 int flg = 0; 59 60 trace2(TR_t_listen, 0, fd); 61 if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL) { 62 sv_errno = errno; 63 trace2(TR_t_listen, 1, fd); 64 errno = sv_errno; 65 return (-1); 66 } 67 68 69 sig_mutex_lock(&tiptr->ti_lock); 70 71 if (tiptr->ti_servtype == T_CLTS) { 72 sv_errno = errno; 73 t_errno = TNOTSUPPORT; 74 sig_mutex_unlock(&tiptr->ti_lock); 75 trace2(TR_t_listen, 1, fd); 76 errno = sv_errno; 77 return (-1); 78 } 79 if (_T_IS_XTI(api_semantics)) { 80 /* 81 * User level state verification only done for XTI 82 * because doing for TLI may break existing applications 83 */ 84 if (! (tiptr->ti_state == T_IDLE || 85 tiptr->ti_state == T_INCON)) { 86 t_errno = TOUTSTATE; 87 sig_mutex_unlock(&tiptr->ti_lock); 88 trace2(TR_t_connect, 1, fd); 89 return (-1); 90 } 91 92 if (tiptr->ti_qlen == 0) { 93 t_errno = TBADQLEN; 94 sig_mutex_unlock(&tiptr->ti_lock); 95 trace2(TR_t_connect, 1, fd); 96 return (-1); 97 } 98 99 if (tiptr->ti_ocnt == tiptr->ti_qlen) { 100 if (!(tiptr->ti_flags & TX_TQFULL_NOTIFIED)) { 101 tiptr->ti_flags |= TX_TQFULL_NOTIFIED; 102 t_errno = TQFULL; 103 sig_mutex_unlock(&tiptr->ti_lock); 104 trace2(TR_t_connect, 1, fd); 105 return (-1); 106 } 107 } 108 109 } 110 111 /* 112 * check if something in look buffer 113 */ 114 if (tiptr->ti_lookcnt > 0) { 115 t_errno = TLOOK; 116 sig_mutex_unlock(&tiptr->ti_lock); 117 trace2(TR_t_listen, 1, fd); 118 return (-1); 119 } 120 121 /* 122 * Acquire ctlbuf for use in sending/receiving control part 123 * of the message. 124 */ 125 if (_t_acquire_ctlbuf(tiptr, &ctlbuf, &didalloc) < 0) { 126 sv_errno = errno; 127 sig_mutex_unlock(&tiptr->ti_lock); 128 trace2(TR_t_listen, 1, fd); 129 errno = sv_errno; 130 return (-1); 131 } 132 /* 133 * Acquire databuf for use in sending/receiving data part 134 */ 135 if (_t_acquire_databuf(tiptr, &databuf, &didralloc) < 0) { 136 int sv_errno = errno; 137 138 if (didalloc) 139 free(ctlbuf.buf); 140 else 141 tiptr->ti_ctlbuf = ctlbuf.buf; 142 sig_mutex_unlock(&tiptr->ti_lock); 143 trace2(TR_t_listen, 1, fd); 144 errno = sv_errno; 145 return (-1); 146 } 147 148 /* 149 * This is a call that may block indefinitely so we drop the 150 * lock and allow signals in MT case here and reacquire it. 151 * Error case should roll back state changes done above 152 * (happens to be no state change here) 153 */ 154 sig_mutex_unlock(&tiptr->ti_lock); 155 if ((retval = getmsg(fd, &ctlbuf, &databuf, &flg)) < 0) { 156 if (errno == EAGAIN) 157 t_errno = TNODATA; 158 else 159 t_errno = TSYSERR; 160 sv_errno = errno; 161 sig_mutex_lock(&tiptr->ti_lock); 162 errno = sv_errno; 163 goto err_out; 164 } 165 sig_mutex_lock(&tiptr->ti_lock); 166 167 if (databuf.len == -1) databuf.len = 0; 168 169 /* 170 * did I get entire message? 171 */ 172 if (retval > 0) { 173 t_errno = TSYSERR; 174 errno = EIO; 175 goto err_out; 176 } 177 178 /* 179 * is ctl part large enough to determine type 180 */ 181 if (ctlbuf.len < (int)sizeof (t_scalar_t)) { 182 t_errno = TSYSERR; 183 errno = EPROTO; 184 goto err_out; 185 } 186 187 pptr = (union T_primitives *)ctlbuf.buf; 188 189 switch (pptr->type) { 190 191 case T_CONN_IND: 192 if ((ctlbuf.len < (int)sizeof (struct T_conn_ind)) || 193 (ctlbuf.len < (int)(pptr->conn_ind.OPT_length 194 + pptr->conn_ind.OPT_offset))) { 195 t_errno = TSYSERR; 196 errno = EPROTO; 197 goto err_out; 198 } 199 /* 200 * Change state and increment outstanding connection 201 * indication count and instantiate "sequence" return 202 * parameter. 203 * Note: It is correct semantics accoring to spec to 204 * do this despite possibility of TBUFOVFLW error later. 205 * The spec treats TBUFOVFLW error in general as a special case 206 * which can be ignored by applications that do not 207 * really need the stuff returned in 'netbuf' structures. 208 */ 209 _T_TX_NEXTSTATE(T_LISTN, tiptr, 210 "t_listen:invalid state event T_LISTN"); 211 tiptr->ti_ocnt++; 212 call->sequence = pptr->conn_ind.SEQ_number; 213 214 if (_T_IS_TLI(api_semantics) || call->addr.maxlen > 0) { 215 if (TLEN_GT_NLEN(pptr->conn_ind.SRC_length, 216 call->addr.maxlen)) { 217 t_errno = TBUFOVFLW; 218 goto err_out; 219 } 220 (void) memcpy(call->addr.buf, ctlbuf.buf + 221 (size_t)pptr->conn_ind.SRC_offset, 222 (unsigned int)pptr->conn_ind.SRC_length); 223 call->addr.len = pptr->conn_ind.SRC_length; 224 } 225 if (_T_IS_TLI(api_semantics) || call->opt.maxlen > 0) { 226 if (TLEN_GT_NLEN(pptr->conn_ind.OPT_length, 227 call->opt.maxlen)) { 228 t_errno = TBUFOVFLW; 229 goto err_out; 230 } 231 (void) memcpy(call->opt.buf, ctlbuf.buf + 232 pptr->conn_ind.OPT_offset, 233 (size_t)pptr->conn_ind.OPT_length); 234 call->opt.len = pptr->conn_ind.OPT_length; 235 } 236 if (_T_IS_TLI(api_semantics) || call->udata.maxlen > 0) { 237 if (databuf.len > (int)call->udata.maxlen) { 238 t_errno = TBUFOVFLW; 239 goto err_out; 240 } 241 (void) memcpy(call->udata.buf, databuf.buf, 242 (size_t)databuf.len); 243 call->udata.len = databuf.len; 244 } 245 246 if (didalloc) 247 free(ctlbuf.buf); 248 else 249 tiptr->ti_ctlbuf = ctlbuf.buf; 250 if (didralloc) 251 free(databuf.buf); 252 else 253 tiptr->ti_rcvbuf = databuf.buf; 254 sig_mutex_unlock(&tiptr->ti_lock); 255 trace2(TR_t_listen, 1, fd); 256 return (0); 257 258 case T_DISCON_IND: 259 /* 260 * Append to the events in the "look buffer" 261 * list of events. This routine may defer signals. 262 */ 263 if (_t_register_lookevent(tiptr, databuf.buf, 264 databuf.len, ctlbuf.buf, 265 ctlbuf.len) < 0) { 266 t_errno = TSYSERR; 267 errno = ENOMEM; 268 goto err_out; 269 } 270 t_errno = TLOOK; 271 goto err_out; 272 273 default: 274 break; 275 } 276 277 t_errno = TSYSERR; 278 errno = EPROTO; 279 err_out: 280 sv_errno = errno; 281 282 if (didalloc) 283 free(ctlbuf.buf); 284 else 285 tiptr->ti_ctlbuf = ctlbuf.buf; 286 if (didralloc) 287 free(databuf.buf); 288 else 289 tiptr->ti_rcvbuf = databuf.buf; 290 sig_mutex_unlock(&tiptr->ti_lock); 291 trace2(TR_t_listen, 1, fd); 292 errno = sv_errno; 293 return (-1); 294 } 295