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