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