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