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