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