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 2006 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.4.3.1 */
32
33 #include "mt.h"
34 #include <errno.h>
35 #include <unistd.h>
36 #include <stropts.h>
37 #include <sys/stream.h>
38 #define _SUN_TPI_VERSION 2
39 #include <sys/tihdr.h>
40 #include <sys/timod.h>
41 #include <xti.h>
42 #include <signal.h>
43 #include <syslog.h>
44 #include "tx.h"
45
46 int
_tx_snddis(int fd,const struct t_call * call,int api_semantics)47 _tx_snddis(int fd, const struct t_call *call, int api_semantics)
48 {
49 struct T_discon_req dreq;
50 struct strbuf ctlbuf;
51 struct strbuf databuf;
52 struct _ti_user *tiptr;
53 int sv_errno;
54 int retval;
55
56 if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL)
57 return (-1);
58 sig_mutex_lock(&tiptr->ti_lock);
59
60 if (tiptr->ti_servtype == T_CLTS) {
61 t_errno = TNOTSUPPORT;
62 sig_mutex_unlock(&tiptr->ti_lock);
63 return (-1);
64 }
65
66 if (_T_IS_XTI(api_semantics)) {
67 /*
68 * User level state verification only done for XTI
69 * because doing for TLI may break existing applications
70 * Note: This is documented in TLI man page but never
71 * done.
72 */
73 if (!(tiptr->ti_state == T_DATAXFER ||
74 tiptr->ti_state == T_OUTCON ||
75 tiptr->ti_state == T_OUTREL ||
76 tiptr->ti_state == T_INREL ||
77 (tiptr->ti_state == T_INCON && tiptr->ti_ocnt > 0))) {
78 t_errno = TOUTSTATE;
79 sig_mutex_unlock(&tiptr->ti_lock);
80 return (-1);
81 }
82
83 /*
84 * Following check only done for XTI as it may be a risk
85 * to existing buggy TLI applications.
86 */
87 }
88
89 if (call != NULL && call->udata.len) {
90 if ((tiptr->ti_ddatasize == T_INVALID /* -2 */) ||
91 ((tiptr->ti_ddatasize != T_INFINITE /* -1*/) &&
92 (call->udata.len >
93 (uint32_t)tiptr->ti_ddatasize))) {
94 /*
95 * user data not valid with disconnect or it
96 * exceeds the limits specified by the
97 * transport provider
98 */
99 t_errno = TBADDATA;
100 sig_mutex_unlock(&tiptr->ti_lock);
101 return (-1);
102 }
103 }
104
105 /*
106 * If disconnect is done on a listener, the 'call' parameter
107 * must be non-null
108 */
109 if ((tiptr->ti_state == T_INCON) &&
110 (call == NULL)) {
111 t_errno = TBADSEQ;
112 sig_mutex_unlock(&tiptr->ti_lock);
113 return (-1);
114 }
115
116 /*
117 * look at look buffer to see if there is a discon there
118 */
119
120 if (_t_look_locked(fd, tiptr, 0, api_semantics) == T_DISCONNECT) {
121 t_errno = TLOOK;
122 sig_mutex_unlock(&tiptr->ti_lock);
123 return (-1);
124 }
125
126 if ((tiptr->ti_lookcnt > 0) && (call == 0))
127 _t_flush_lookevents(tiptr); /* flush but not on listener */
128
129 do {
130 retval = ioctl(fd, I_FLUSH, FLUSHW);
131 } while (retval < 0 && errno == EINTR);
132 if (retval < 0) {
133 sv_errno = errno;
134 t_errno = TSYSERR;
135 sig_mutex_unlock(&tiptr->ti_lock);
136 errno = sv_errno;
137 return (-1);
138 }
139
140 ctlbuf.len = (int)sizeof (struct T_discon_req);
141 ctlbuf.maxlen = (int)sizeof (struct T_discon_req);
142 ctlbuf.buf = (char *)&dreq;
143
144 dreq.PRIM_type = T_DISCON_REQ;
145 dreq.SEQ_number = (call? call->sequence: -1);
146
147 databuf.maxlen = (call? call->udata.len: 0);
148 databuf.len = (call? call->udata.len: 0);
149 databuf.buf = (call? call->udata.buf: NULL);
150
151 /*
152 * Calls to send data (write or putmsg) can potentially
153 * block, for MT case, we drop the lock and enable signals here
154 * and acquire it back
155 */
156 sig_mutex_unlock(&tiptr->ti_lock);
157 if (putmsg(fd, &ctlbuf, (databuf.len? &databuf: NULL), 0) < 0) {
158 t_errno = TSYSERR;
159 return (-1);
160 }
161 sig_mutex_lock(&tiptr->ti_lock);
162
163 if (_t_is_ok(fd, tiptr, T_DISCON_REQ) < 0) {
164 sv_errno = errno;
165 sig_mutex_unlock(&tiptr->ti_lock);
166 errno = sv_errno;
167 return (-1);
168 }
169
170 tiptr->ti_flags &= ~(MORE|EXPEDITED);
171
172 if (tiptr->ti_ocnt <= 1) {
173 if (tiptr->ti_state == T_INCON) {
174 tiptr->ti_ocnt--;
175 tiptr->ti_flags &= ~TX_TQFULL_NOTIFIED;
176 }
177 _T_TX_NEXTSTATE(T_SNDDIS1, tiptr,
178 "t_snddis: invalid state event T_SNDDIS1");
179 } else {
180 if (tiptr->ti_state == T_INCON) {
181 tiptr->ti_ocnt--;
182 tiptr->ti_flags &= ~TX_TQFULL_NOTIFIED;
183 }
184 _T_TX_NEXTSTATE(T_SNDDIS2, tiptr,
185 "t_snddis: invalid state event T_SNDDIS2");
186 }
187
188 sig_mutex_unlock(&tiptr->ti_lock);
189 return (0);
190 }
191