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