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