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