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
_tx_listen(int fd,struct t_call * call,int api_semantics)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