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 1998-2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 /* 31 * t_rcvudata.c and t_rcvvudata.c are very similar and contain common code. 32 * Any changes to either of them should be reviewed to see whether they 33 * are applicable to the other file. 34 */ 35 #include "mt.h" 36 #include <rpc/trace.h> 37 #include <string.h> 38 #include <stdlib.h> 39 #include <errno.h> 40 #include <stropts.h> 41 #include <sys/stream.h> 42 #define _SUN_TPI_VERSION 2 43 #include <sys/tihdr.h> 44 #include <sys/timod.h> 45 #include <xti.h> 46 #include <syslog.h> 47 #include <assert.h> 48 #include "tx.h" 49 50 51 int 52 _tx_rcvvudata( 53 int fd, 54 struct t_unitdata *unitdata, 55 struct t_iovec *tiov, 56 unsigned int tiovcount, 57 int *flags, 58 int api_semantics 59 ) 60 { 61 struct strbuf ctlbuf; 62 struct strbuf databuf; 63 char *dataptr; 64 int retval; 65 union T_primitives *pptr; 66 struct _ti_user *tiptr; 67 int sv_errno; 68 int didalloc; 69 int flg = 0; 70 unsigned int nbytes; 71 72 trace2(TR_t_rcvvudata, 0, fd); 73 assert(api_semantics == TX_XTI_XNS5_API); 74 75 if (tiovcount == 0 || tiovcount > T_IOV_MAX) { 76 t_errno = TBADDATA; 77 return (-1); 78 } 79 80 if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL) { 81 sv_errno = errno; 82 trace2(TR_t_rcvvudata, 1, fd); 83 errno = sv_errno; 84 return (-1); 85 } 86 sig_mutex_lock(&tiptr->ti_lock); 87 88 if (tiptr->ti_servtype != T_CLTS) { 89 t_errno = TNOTSUPPORT; 90 sig_mutex_unlock(&tiptr->ti_lock); 91 trace2(TR_t_rcvvudata, 1, fd); 92 return (-1); 93 } 94 95 if (tiptr->ti_state != T_IDLE) { 96 t_errno = TOUTSTATE; 97 sig_mutex_unlock(&tiptr->ti_lock); 98 trace2(TR_t_rcvvudata, 1, fd); 99 return (-1); 100 } 101 102 /* 103 * check if there is something in look buffer 104 */ 105 if (tiptr->ti_lookcnt > 0) { 106 sig_mutex_unlock(&tiptr->ti_lock); 107 trace2(TR_t_rcvvudata, 1, fd); 108 t_errno = TLOOK; 109 return (-1); 110 } 111 112 /* 113 * Acquire ctlbuf for use in sending/receiving control part 114 * of the message. 115 */ 116 if (_t_acquire_ctlbuf(tiptr, &ctlbuf, &didalloc) < 0) { 117 sv_errno = errno; 118 sig_mutex_unlock(&tiptr->ti_lock); 119 trace2(TR_t_rcvvudata, 1, fd); 120 errno = sv_errno; 121 return (-1); 122 } 123 124 *flags = 0; 125 126 nbytes = _t_bytecount_upto_intmax(tiov, tiovcount); 127 dataptr = NULL; 128 if (nbytes != 0 && ((dataptr = malloc(nbytes)) == NULL)) { 129 t_errno = TSYSERR; 130 goto err_out; 131 } 132 133 databuf.maxlen = nbytes; 134 databuf.len = 0; 135 databuf.buf = dataptr; 136 137 /* 138 * This is a call that may block indefinitely so we drop the 139 * lock and allow signals in MT case here and reacquire it. 140 * Error case should roll back state changes done above 141 * (happens to be no state change here) 142 */ 143 sig_mutex_unlock(&tiptr->ti_lock); 144 if ((retval = getmsg(fd, &ctlbuf, &databuf, &flg)) < 0) { 145 if (errno == EAGAIN) 146 t_errno = TNODATA; 147 else 148 t_errno = TSYSERR; 149 sv_errno = errno; 150 sig_mutex_lock(&tiptr->ti_lock); 151 errno = sv_errno; 152 goto err_out; 153 } 154 sig_mutex_lock(&tiptr->ti_lock); 155 156 /* 157 * is there control piece with data? 158 */ 159 if (ctlbuf.len > 0) { 160 if (ctlbuf.len < (int)sizeof (t_scalar_t)) { 161 t_errno = TSYSERR; 162 errno = EPROTO; 163 goto err_out; 164 } 165 166 pptr = (union T_primitives *)ctlbuf.buf; 167 168 switch (pptr->type) { 169 170 case T_UNITDATA_IND: 171 if ((ctlbuf.len < 172 (int)sizeof (struct T_unitdata_ind)) || 173 (pptr->unitdata_ind.OPT_length && 174 (ctlbuf.len < (int)(pptr->unitdata_ind.OPT_length 175 + pptr->unitdata_ind.OPT_offset)))) { 176 t_errno = TSYSERR; 177 errno = EPROTO; 178 goto err_out; 179 } 180 181 if (unitdata->addr.maxlen > 0) { 182 if (TLEN_GT_NLEN(pptr->unitdata_ind.SRC_length, 183 unitdata->addr.maxlen)) { 184 t_errno = TBUFOVFLW; 185 goto err_out; 186 } 187 (void) memcpy(unitdata->addr.buf, 188 ctlbuf.buf + pptr->unitdata_ind.SRC_offset, 189 (size_t)pptr->unitdata_ind.SRC_length); 190 unitdata->addr.len = 191 pptr->unitdata_ind.SRC_length; 192 } 193 if (unitdata->opt.maxlen > 0) { 194 if (TLEN_GT_NLEN(pptr->unitdata_ind.OPT_length, 195 unitdata->opt.maxlen)) { 196 t_errno = TBUFOVFLW; 197 goto err_out; 198 } 199 (void) memcpy(unitdata->opt.buf, ctlbuf.buf + 200 pptr->unitdata_ind.OPT_offset, 201 (size_t)pptr->unitdata_ind.OPT_length); 202 unitdata->opt.len = 203 pptr->unitdata_ind.OPT_length; 204 } 205 if (retval & MOREDATA) 206 *flags |= T_MORE; 207 /* 208 * No state changes happens on T_RCVUDATA 209 * event (NOOP). We do it only to log errors. 210 */ 211 _T_TX_NEXTSTATE(T_RCVUDATA, tiptr, 212 "t_rcvvudata: invalid state event T_RCVUDATA"); 213 214 if (didalloc) 215 free(ctlbuf.buf); 216 else 217 tiptr->ti_ctlbuf = ctlbuf.buf; 218 _t_scatter(&databuf, tiov, tiovcount); 219 if (dataptr != NULL) 220 free(dataptr); 221 sig_mutex_unlock(&tiptr->ti_lock); 222 trace2(TR_t_rcvvudata, 1, fd); 223 return (databuf.len); 224 225 case T_UDERROR_IND: 226 if (_t_register_lookevent(tiptr, 0, 0, ctlbuf.buf, 227 ctlbuf.len) < 0) { 228 t_errno = TSYSERR; 229 errno = ENOMEM; 230 goto err_out; 231 } 232 t_errno = TLOOK; 233 goto err_out; 234 235 default: 236 break; 237 } 238 239 t_errno = TSYSERR; 240 errno = EPROTO; 241 goto err_out; 242 243 } else { /* else part of "if (ctlbuf.len > 0)" */ 244 unitdata->addr.len = 0; 245 unitdata->opt.len = 0; 246 /* 247 * only data in message no control piece 248 */ 249 if (retval & MOREDATA) 250 *flags = T_MORE; 251 /* 252 * No state transition occurs on 253 * event T_RCVUDATA. We do it only to 254 * log errors. 255 */ 256 _T_TX_NEXTSTATE(T_RCVUDATA, tiptr, 257 "t_rcvvudata: invalid state event T_RCVUDATA"); 258 if (didalloc) 259 free(ctlbuf.buf); 260 else 261 tiptr->ti_ctlbuf = ctlbuf.buf; 262 _t_scatter(&databuf, tiov, tiovcount); 263 if (dataptr != NULL) 264 free(dataptr); 265 sig_mutex_unlock(&tiptr->ti_lock); 266 trace2(TR_t_rcvvudata, 0, fd); 267 return (databuf.len); 268 } 269 /* NOTREACHED */ 270 err_out: 271 sv_errno = errno; 272 if (didalloc) 273 free(ctlbuf.buf); 274 else 275 tiptr->ti_ctlbuf = ctlbuf.buf; 276 if (dataptr != NULL) 277 free(dataptr); 278 sig_mutex_unlock(&tiptr->ti_lock); 279 trace2(TR_t_rcvvudata, 1, fd); 280 errno = sv_errno; 281 return (-1); 282 } 283