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.10 */
32
33 #include "mt.h"
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.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 <signal.h>
44 #include <syslog.h>
45 #include "tx.h"
46
47 int
_tx_rcvdis(int fd,struct t_discon * discon,int api_semantics)48 _tx_rcvdis(int fd, struct t_discon *discon, int api_semantics)
49 {
50 struct strbuf ctlbuf;
51 struct strbuf databuf;
52 int retval;
53 union T_primitives *pptr;
54 struct _ti_user *tiptr;
55 int sv_errno;
56 int flg = 0;
57 int didalloc, didralloc;
58 int use_lookbufs = 0;
59
60 if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL)
61 return (-1);
62
63 /*
64 * Acquire per thread lock.
65 * Note: Lock is held across most of this routine
66 * including the blocking getmsg() call. This is fine
67 * because it is first verfied that an event is pending
68 */
69 sig_mutex_lock(&tiptr->ti_lock);
70
71 if (tiptr->ti_servtype == T_CLTS) {
72 t_errno = TNOTSUPPORT;
73 sig_mutex_unlock(&tiptr->ti_lock);
74 return (-1);
75 }
76
77 if (_T_IS_XTI(api_semantics)) {
78 /*
79 * User level state verification only done for XTI
80 * because doing for TLI may break existing applications
81 */
82 if (!(tiptr->ti_state == T_DATAXFER ||
83 tiptr->ti_state == T_OUTCON ||
84 tiptr->ti_state == T_OUTREL ||
85 tiptr->ti_state == T_INREL ||
86 (tiptr->ti_state == T_INCON && tiptr->ti_ocnt > 0))) {
87 t_errno = TOUTSTATE;
88 sig_mutex_unlock(&tiptr->ti_lock);
89 return (-1);
90 }
91 }
92 /*
93 * Handle likely scenario as special case:
94 * Is there a discon in look buffer as the first
95 * event in the lookbuffer, is so just get it.
96 */
97 if ((tiptr->ti_lookcnt > 0) &&
98 /* LINTED pointer cast */
99 (*((t_scalar_t *)tiptr->ti_lookbufs.tl_lookcbuf) == T_DISCON_IND)) {
100 /*
101 * The T_DISCON_IND is already in the look buffer
102 */
103 ctlbuf.len = tiptr->ti_lookbufs.tl_lookclen;
104 ctlbuf.buf = tiptr->ti_lookbufs.tl_lookcbuf;
105 /* Note: ctlbuf.maxlen not used in this case */
106
107 databuf.len = tiptr->ti_lookbufs.tl_lookdlen;
108 databuf.buf = tiptr->ti_lookbufs.tl_lookdbuf;
109 /* Note databuf.maxlen not used in this case */
110
111 use_lookbufs = 1;
112
113 } else {
114
115 if ((retval = _t_look_locked(fd, tiptr, 0,
116 api_semantics)) < 0) {
117 sv_errno = errno;
118 sig_mutex_unlock(&tiptr->ti_lock);
119 errno = sv_errno;
120 return (-1);
121 }
122
123 if (retval != T_DISCONNECT) {
124 t_errno = TNODIS;
125 sig_mutex_unlock(&tiptr->ti_lock);
126 return (-1);
127 }
128
129 /*
130 * get disconnect off read queue.
131 * use ctl and rcv buffers
132 *
133 * Acquire ctlbuf for use in sending/receiving control part
134 * of the message.
135 */
136 if (_t_acquire_ctlbuf(tiptr, &ctlbuf, &didalloc) < 0) {
137 sv_errno = errno;
138 sig_mutex_unlock(&tiptr->ti_lock);
139 errno = sv_errno;
140 return (-1);
141 }
142
143 /*
144 * Acquire databuf for use in sending/receiving data part
145 */
146 if (_t_acquire_databuf(tiptr, &databuf, &didralloc) < 0) {
147 sv_errno = errno;
148 if (didalloc)
149 free(ctlbuf.buf);
150 else
151 tiptr->ti_ctlbuf = ctlbuf.buf;
152 sig_mutex_unlock(&tiptr->ti_lock);
153 errno = sv_errno;
154 return (-1);
155 }
156
157 /*
158 * Since we already verified that a disconnect event
159 * is present, we assume that this getmsg() cannot
160 * block indefinitely
161 */
162 do {
163 retval = getmsg(fd, &ctlbuf, &databuf, &flg);
164 } while (retval < 0 && errno == EINTR);
165
166 if (retval < 0) {
167 t_errno = TSYSERR;
168 goto err_out;
169 }
170 if (databuf.len == -1) databuf.len = 0;
171
172 /*
173 * did I get entire message?
174 */
175 if (retval > 0) {
176 t_errno = TSYSERR;
177 errno = EIO;
178 goto err_out;
179 }
180 }
181
182
183 /* LINTED pointer cast */
184 pptr = (union T_primitives *)ctlbuf.buf;
185
186 if ((ctlbuf.len < (int)sizeof (struct T_discon_ind)) ||
187 (pptr->type != T_DISCON_IND)) {
188 t_errno = TSYSERR;
189 errno = EPROTO;
190 goto err_out;
191 }
192
193 /*
194 * clear more and expedited flags
195 */
196 tiptr->ti_flags &= ~(MORE | EXPEDITED);
197
198 if (tiptr->ti_ocnt <= 0) {
199 _T_TX_NEXTSTATE(T_RCVDIS1, tiptr,
200 "t_rcvdis: invalid state event T_RCVDIS1");
201 } else {
202 if (tiptr->ti_ocnt == 1) {
203 _T_TX_NEXTSTATE(T_RCVDIS2, tiptr,
204 "t_rcvdis: invalid state event T_RCVDIS2");
205 } else {
206 _T_TX_NEXTSTATE(T_RCVDIS3, tiptr,
207 "t_rcvdis: invalid state event T_RCVDIS3");
208 }
209 tiptr->ti_ocnt--;
210 tiptr->ti_flags &= ~TX_TQFULL_NOTIFIED;
211 }
212
213 if (discon != NULL) {
214 if (_T_IS_TLI(api_semantics) || discon->udata.maxlen > 0) {
215 if (databuf.len > (int)discon->udata.maxlen) {
216 t_errno = TBUFOVFLW;
217 goto err_out;
218 }
219 (void) memcpy(discon->udata.buf, databuf.buf,
220 (size_t)databuf.len);
221 discon->udata.len = databuf.len;
222 }
223 discon->reason = pptr->discon_ind.DISCON_reason;
224 discon->sequence = pptr->discon_ind.SEQ_number;
225 }
226 if (use_lookbufs)
227 _t_free_looklist_head(tiptr);
228 else {
229 if (didalloc)
230 free(ctlbuf.buf);
231 else
232 tiptr->ti_ctlbuf = ctlbuf.buf;
233 if (didralloc)
234 free(databuf.buf);
235 else
236 tiptr->ti_rcvbuf = databuf.buf;
237 }
238 sig_mutex_unlock(&tiptr->ti_lock);
239 return (0);
240
241 err_out:
242 sv_errno = errno;
243
244 if (use_lookbufs)
245 _t_free_looklist_head(tiptr);
246 else {
247 if (didalloc)
248 free(ctlbuf.buf);
249 else
250 tiptr->ti_ctlbuf = ctlbuf.buf;
251 if (didralloc)
252 free(databuf.buf);
253 else
254 tiptr->ti_rcvbuf = databuf.buf;
255 }
256 sig_mutex_unlock(&tiptr->ti_lock);
257 errno = sv_errno;
258 return (-1);
259 }
260