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