1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #include "mt.h" 31*0Sstevel@tonic-gate #include <rpc/trace.h> 32*0Sstevel@tonic-gate #include <unistd.h> 33*0Sstevel@tonic-gate #include <stdlib.h> 34*0Sstevel@tonic-gate #include <errno.h> 35*0Sstevel@tonic-gate #include <stropts.h> 36*0Sstevel@tonic-gate #include <sys/stream.h> 37*0Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 38*0Sstevel@tonic-gate #include <sys/tihdr.h> 39*0Sstevel@tonic-gate #include <sys/timod.h> 40*0Sstevel@tonic-gate #include <xti.h> 41*0Sstevel@tonic-gate #include <assert.h> 42*0Sstevel@tonic-gate #include <syslog.h> 43*0Sstevel@tonic-gate #include "tx.h" 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate /* 47*0Sstevel@tonic-gate * t_snd.c and t_sndv.c are very similar and contain common code. 48*0Sstevel@tonic-gate * Any changes to either of them should be reviewed to see whether they 49*0Sstevel@tonic-gate * are applicable to the other file. 50*0Sstevel@tonic-gate */ 51*0Sstevel@tonic-gate int 52*0Sstevel@tonic-gate _tx_sndv(int fd, const struct t_iovec *tiov, unsigned int tiovcount, 53*0Sstevel@tonic-gate int flags, int api_semantics) 54*0Sstevel@tonic-gate { 55*0Sstevel@tonic-gate struct T_data_req datareq; 56*0Sstevel@tonic-gate struct strbuf ctlbuf, databuf; 57*0Sstevel@tonic-gate unsigned int bytes_sent, bytes_remaining, bytes_to_send, nbytes; 58*0Sstevel@tonic-gate char *curptr; 59*0Sstevel@tonic-gate struct iovec iov[T_IOV_MAX]; 60*0Sstevel@tonic-gate int iovcount; 61*0Sstevel@tonic-gate char *dataptr; 62*0Sstevel@tonic-gate int first_time; 63*0Sstevel@tonic-gate struct _ti_user *tiptr; 64*0Sstevel@tonic-gate int band; 65*0Sstevel@tonic-gate int retval, lookevent; 66*0Sstevel@tonic-gate int sv_errno; 67*0Sstevel@tonic-gate int doputmsg = 0; 68*0Sstevel@tonic-gate int32_t tsdu_limit; 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate trace5(TR_t_sndv, 0, fd, tiov, tiovcount, flags); 71*0Sstevel@tonic-gate assert(api_semantics == TX_XTI_XNS5_API); 72*0Sstevel@tonic-gate if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL) { 73*0Sstevel@tonic-gate sv_errno = errno; 74*0Sstevel@tonic-gate trace5(TR_t_sndv, 1, fd, tiov, tiovcount, flags); 75*0Sstevel@tonic-gate errno = sv_errno; 76*0Sstevel@tonic-gate return (-1); 77*0Sstevel@tonic-gate } 78*0Sstevel@tonic-gate sig_mutex_lock(&tiptr->ti_lock); 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate if (tiptr->ti_servtype == T_CLTS) { 81*0Sstevel@tonic-gate t_errno = TNOTSUPPORT; 82*0Sstevel@tonic-gate sig_mutex_unlock(&tiptr->ti_lock); 83*0Sstevel@tonic-gate trace5(TR_t_sndv, 1, fd, tiov, tiovcount, flags); 84*0Sstevel@tonic-gate return (-1); 85*0Sstevel@tonic-gate } 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate if (tiovcount == 0 || tiovcount > T_IOV_MAX) { 88*0Sstevel@tonic-gate t_errno = TBADDATA; 89*0Sstevel@tonic-gate sig_mutex_unlock(&tiptr->ti_lock); 90*0Sstevel@tonic-gate trace5(TR_t_sndv, 1, fd, tiov, tiovcount, flags); 91*0Sstevel@tonic-gate return (-1); 92*0Sstevel@tonic-gate } 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate if (! (tiptr->ti_state == T_DATAXFER || 95*0Sstevel@tonic-gate tiptr->ti_state == T_INREL)) { 96*0Sstevel@tonic-gate t_errno = TOUTSTATE; 97*0Sstevel@tonic-gate sig_mutex_unlock(&tiptr->ti_lock); 98*0Sstevel@tonic-gate trace5(TR_t_sndv, 1, fd, tiov, tiovcount, flags); 99*0Sstevel@tonic-gate return (-1); 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate /* 102*0Sstevel@tonic-gate * XXX 103*0Sstevel@tonic-gate * Is it OK to do this TBADFLAG check when XTI spec 104*0Sstevel@tonic-gate * is being extended with new and interesting flags 105*0Sstevel@tonic-gate * everyday ? 106*0Sstevel@tonic-gate */ 107*0Sstevel@tonic-gate if ((flags & ~(TX_ALL_VALID_FLAGS)) != 0) { 108*0Sstevel@tonic-gate t_errno = TBADFLAG; 109*0Sstevel@tonic-gate sig_mutex_unlock(&tiptr->ti_lock); 110*0Sstevel@tonic-gate trace5(TR_t_sndv, 1, fd, tiov, tiovcount, flags); 111*0Sstevel@tonic-gate return (-1); 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate if (flags & T_EXPEDITED) 114*0Sstevel@tonic-gate tsdu_limit = tiptr->ti_etsdusize; 115*0Sstevel@tonic-gate else { 116*0Sstevel@tonic-gate /* normal data */ 117*0Sstevel@tonic-gate tsdu_limit = tiptr->ti_tsdusize; 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate /* 121*0Sstevel@tonic-gate * nbytes is the sum of the bytecounts in the tiov vector 122*0Sstevel@tonic-gate * A value larger than INT_MAX is truncated to INT_MAX by 123*0Sstevel@tonic-gate * _t_bytecount_upto_intmax() 124*0Sstevel@tonic-gate */ 125*0Sstevel@tonic-gate nbytes = _t_bytecount_upto_intmax(tiov, tiovcount); 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate if ((tsdu_limit > 0) && /* limit meaningful and ... */ 128*0Sstevel@tonic-gate (nbytes > (uint32_t)tsdu_limit)) { 129*0Sstevel@tonic-gate t_errno = TBADDATA; 130*0Sstevel@tonic-gate sig_mutex_unlock(&tiptr->ti_lock); 131*0Sstevel@tonic-gate trace5(TR_t_sndv, 1, fd, tiov, tiovcount, flags); 132*0Sstevel@tonic-gate return (-1); 133*0Sstevel@tonic-gate } 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate /* 136*0Sstevel@tonic-gate * Check for incoming disconnect only. XNS Issue 5 makes it optional 137*0Sstevel@tonic-gate * to check for incoming orderly release 138*0Sstevel@tonic-gate */ 139*0Sstevel@tonic-gate lookevent = _t_look_locked(fd, tiptr, 0, api_semantics); 140*0Sstevel@tonic-gate if (lookevent < 0) { 141*0Sstevel@tonic-gate sv_errno = errno; 142*0Sstevel@tonic-gate sig_mutex_unlock(&tiptr->ti_lock); 143*0Sstevel@tonic-gate trace5(TR_t_sndv, 1, fd, tiov, tiovcount, flags); 144*0Sstevel@tonic-gate errno = sv_errno; 145*0Sstevel@tonic-gate return (-1); 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate if (lookevent == T_DISCONNECT) { 148*0Sstevel@tonic-gate t_errno = TLOOK; 149*0Sstevel@tonic-gate sig_mutex_unlock(&tiptr->ti_lock); 150*0Sstevel@tonic-gate trace5(TR_t_sndv, 1, fd, tiov, tiovcount, flags); 151*0Sstevel@tonic-gate return (-1); 152*0Sstevel@tonic-gate } 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate /* sending zero length data when not allowed */ 155*0Sstevel@tonic-gate if (nbytes == 0 && !(tiptr->ti_prov_flag & (SENDZERO|OLD_SENDZERO))) { 156*0Sstevel@tonic-gate t_errno = TBADDATA; 157*0Sstevel@tonic-gate sig_mutex_unlock(&tiptr->ti_lock); 158*0Sstevel@tonic-gate trace5(TR_t_sndv, 1, fd, tiov, tiovcount, flags); 159*0Sstevel@tonic-gate return (-1); 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate doputmsg = (tiptr->ti_tsdusize != 0) || (flags & T_EXPEDITED); 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate if (doputmsg) { 165*0Sstevel@tonic-gate /* 166*0Sstevel@tonic-gate * Initialize ctlbuf for use in sending/receiving control part 167*0Sstevel@tonic-gate * of the message. 168*0Sstevel@tonic-gate */ 169*0Sstevel@tonic-gate ctlbuf.maxlen = (int)sizeof (struct T_data_req); 170*0Sstevel@tonic-gate ctlbuf.len = (int)sizeof (struct T_data_req); 171*0Sstevel@tonic-gate ctlbuf.buf = (char *)&datareq; 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate band = TI_NORMAL; /* band 0 */ 174*0Sstevel@tonic-gate if (flags & T_EXPEDITED) { 175*0Sstevel@tonic-gate datareq.PRIM_type = T_EXDATA_REQ; 176*0Sstevel@tonic-gate if (! (tiptr->ti_prov_flag & EXPINLINE)) 177*0Sstevel@tonic-gate band = TI_EXPEDITED; /* band > 0 */ 178*0Sstevel@tonic-gate } else 179*0Sstevel@tonic-gate datareq.PRIM_type = T_DATA_REQ; 180*0Sstevel@tonic-gate /* 181*0Sstevel@tonic-gate * Allocate a databuffer into which we will gather the 182*0Sstevel@tonic-gate * input vector data, and make a call to putmsg(). We 183*0Sstevel@tonic-gate * do this since we don't have the equivalent of a putmsgv() 184*0Sstevel@tonic-gate */ 185*0Sstevel@tonic-gate if (nbytes != 0) { 186*0Sstevel@tonic-gate if ((dataptr = malloc((size_t)nbytes)) == NULL) { 187*0Sstevel@tonic-gate sv_errno = errno; 188*0Sstevel@tonic-gate sig_mutex_unlock(&tiptr->ti_lock); 189*0Sstevel@tonic-gate trace5(TR_t_sndv, 1, fd, tiov, tiovcount, 190*0Sstevel@tonic-gate flags); 191*0Sstevel@tonic-gate errno = sv_errno; 192*0Sstevel@tonic-gate t_errno = TSYSERR; 193*0Sstevel@tonic-gate return (-1); /* error */ 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate /* 196*0Sstevel@tonic-gate * Gather the input buffers, into the single linear 197*0Sstevel@tonic-gate * buffer allocated above, while taking care to see 198*0Sstevel@tonic-gate * that no more than INT_MAX bytes will be copied. 199*0Sstevel@tonic-gate */ 200*0Sstevel@tonic-gate _t_gather(dataptr, tiov, tiovcount); 201*0Sstevel@tonic-gate curptr = dataptr; /* Initialize for subsequent use */ 202*0Sstevel@tonic-gate } else { 203*0Sstevel@tonic-gate dataptr = NULL; 204*0Sstevel@tonic-gate curptr = NULL; 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate bytes_remaining = nbytes; 209*0Sstevel@tonic-gate /* 210*0Sstevel@tonic-gate * Calls to send data (write or putmsg) can potentially 211*0Sstevel@tonic-gate * block, for MT case, we drop the lock and enable signals here 212*0Sstevel@tonic-gate * and acquire it back 213*0Sstevel@tonic-gate */ 214*0Sstevel@tonic-gate sig_mutex_unlock(&tiptr->ti_lock); 215*0Sstevel@tonic-gate first_time = 1; 216*0Sstevel@tonic-gate do { 217*0Sstevel@tonic-gate bytes_to_send = bytes_remaining; 218*0Sstevel@tonic-gate if (doputmsg) { 219*0Sstevel@tonic-gate /* 220*0Sstevel@tonic-gate * transport provider supports TSDU concept 221*0Sstevel@tonic-gate * (unlike TCP) or it is expedited data. 222*0Sstevel@tonic-gate * In this case do the fragmentation 223*0Sstevel@tonic-gate */ 224*0Sstevel@tonic-gate if (bytes_to_send > (unsigned int)tiptr->ti_maxpsz) { 225*0Sstevel@tonic-gate datareq.MORE_flag = 1; 226*0Sstevel@tonic-gate bytes_to_send = (unsigned int)tiptr->ti_maxpsz; 227*0Sstevel@tonic-gate } else { 228*0Sstevel@tonic-gate if (flags&T_MORE) 229*0Sstevel@tonic-gate datareq.MORE_flag = 1; 230*0Sstevel@tonic-gate else 231*0Sstevel@tonic-gate datareq.MORE_flag = 0; 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate databuf.maxlen = bytes_to_send; 234*0Sstevel@tonic-gate databuf.len = bytes_to_send; 235*0Sstevel@tonic-gate databuf.buf = curptr; 236*0Sstevel@tonic-gate retval = putpmsg(fd, &ctlbuf, &databuf, band, MSG_BAND); 237*0Sstevel@tonic-gate if (retval == 0) { 238*0Sstevel@tonic-gate bytes_sent = bytes_to_send; 239*0Sstevel@tonic-gate curptr = curptr + bytes_sent; 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate } else { 242*0Sstevel@tonic-gate /* 243*0Sstevel@tonic-gate * transport provider does *not* support TSDU concept 244*0Sstevel@tonic-gate * (e.g. TCP) and it is not expedited data. A 245*0Sstevel@tonic-gate * perf. optimization is used. Note: the T_MORE 246*0Sstevel@tonic-gate * flag is ignored here even if set by the user. 247*0Sstevel@tonic-gate */ 248*0Sstevel@tonic-gate /* 249*0Sstevel@tonic-gate * The first time, setup the tiovec for doing a writev 250*0Sstevel@tonic-gate * call. We assume that T_IOV_MAX <= IOV_MAX. 251*0Sstevel@tonic-gate * Since writev may return a partial count, we need 252*0Sstevel@tonic-gate * the loop. After the first time, we just adjust 253*0Sstevel@tonic-gate * the iov vector to not include the already 254*0Sstevel@tonic-gate * written bytes. 255*0Sstevel@tonic-gate */ 256*0Sstevel@tonic-gate if (first_time) { 257*0Sstevel@tonic-gate first_time = 0; 258*0Sstevel@tonic-gate _t_copy_tiov_to_iov(tiov, tiovcount, iov, 259*0Sstevel@tonic-gate &iovcount); 260*0Sstevel@tonic-gate } else { 261*0Sstevel@tonic-gate /* 262*0Sstevel@tonic-gate * bytes_sent - value set below in the previous 263*0Sstevel@tonic-gate * iteration of the loop is used now. 264*0Sstevel@tonic-gate */ 265*0Sstevel@tonic-gate _t_adjust_iov(bytes_sent, iov, &iovcount); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate retval = (int)writev(fd, iov, iovcount); 268*0Sstevel@tonic-gate if (retval >= 0) { 269*0Sstevel@tonic-gate /* Amount that was actually sent */ 270*0Sstevel@tonic-gate bytes_sent = retval; 271*0Sstevel@tonic-gate } 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate if (retval < 0) { 275*0Sstevel@tonic-gate if (nbytes == bytes_remaining) { 276*0Sstevel@tonic-gate /* 277*0Sstevel@tonic-gate * Error on *first* putmsg/write attempt. 278*0Sstevel@tonic-gate * Return appropriate error 279*0Sstevel@tonic-gate */ 280*0Sstevel@tonic-gate if (errno == EAGAIN) 281*0Sstevel@tonic-gate t_errno = TFLOW; 282*0Sstevel@tonic-gate else 283*0Sstevel@tonic-gate t_errno = TSYSERR; 284*0Sstevel@tonic-gate if (dataptr) 285*0Sstevel@tonic-gate free(dataptr); 286*0Sstevel@tonic-gate sv_errno = errno; 287*0Sstevel@tonic-gate trace5(TR_t_sndv, 1, fd, tiov, tiovcount, 288*0Sstevel@tonic-gate flags); 289*0Sstevel@tonic-gate errno = sv_errno; 290*0Sstevel@tonic-gate return (-1); /* return error */ 291*0Sstevel@tonic-gate } else { 292*0Sstevel@tonic-gate /* 293*0Sstevel@tonic-gate * Not the first putmsg/write 294*0Sstevel@tonic-gate * [ partial completion of t_snd() case. 295*0Sstevel@tonic-gate * 296*0Sstevel@tonic-gate * Error on putmsg/write attempt but 297*0Sstevel@tonic-gate * some data was transmitted so don't 298*0Sstevel@tonic-gate * return error. Don't attempt to 299*0Sstevel@tonic-gate * send more (break from loop) but 300*0Sstevel@tonic-gate * return OK. 301*0Sstevel@tonic-gate */ 302*0Sstevel@tonic-gate break; 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate bytes_remaining = bytes_remaining - bytes_sent; 306*0Sstevel@tonic-gate } while (bytes_remaining != 0); 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate if (dataptr != NULL) 309*0Sstevel@tonic-gate free(dataptr); 310*0Sstevel@tonic-gate _T_TX_NEXTSTATE(T_SND, tiptr, "t_snd: invalid state event T_SND"); 311*0Sstevel@tonic-gate sv_errno = errno; 312*0Sstevel@tonic-gate trace5(TR_t_sndv, 0, fd, tiov, tiovcount, flags); 313*0Sstevel@tonic-gate errno = sv_errno; 314*0Sstevel@tonic-gate return (nbytes - bytes_remaining); 315*0Sstevel@tonic-gate } 316