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 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