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