4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
32 #include <sys/stream.h>
33 #define _SUN_TPI_VERSION 2
34 #include <sys/tihdr.h>
35 #include <sys/timod.h>
43 * t_snd.c and t_sndv.c are very similar and contain common code.
44 * Any changes to either of them should be reviewed to see whether they
45 * are applicable to the other file.
48 _tx_sndv(int fd
, const struct t_iovec
*tiov
, unsigned int tiovcount
,
49 int flags
, int api_semantics
)
51 struct T_data_req datareq
;
52 struct strbuf ctlbuf
, databuf
;
53 unsigned int bytes_sent
, bytes_remaining
, bytes_to_send
, nbytes
;
55 struct iovec iov
[T_IOV_MAX
];
59 struct _ti_user
*tiptr
;
61 int retval
, lookevent
;
66 assert(api_semantics
== TX_XTI_XNS5_API
);
67 if ((tiptr
= _t_checkfd(fd
, 0, api_semantics
)) == NULL
)
69 sig_mutex_lock(&tiptr
->ti_lock
);
71 if (tiptr
->ti_servtype
== T_CLTS
) {
72 t_errno
= TNOTSUPPORT
;
73 sig_mutex_unlock(&tiptr
->ti_lock
);
77 if (tiovcount
== 0 || tiovcount
> T_IOV_MAX
) {
79 sig_mutex_unlock(&tiptr
->ti_lock
);
83 if (!(tiptr
->ti_state
== T_DATAXFER
||
84 tiptr
->ti_state
== T_INREL
)) {
86 sig_mutex_unlock(&tiptr
->ti_lock
);
91 * Is it OK to do this TBADFLAG check when XTI spec
92 * is being extended with new and interesting flags
95 if ((flags
& ~(TX_ALL_VALID_FLAGS
)) != 0) {
97 sig_mutex_unlock(&tiptr
->ti_lock
);
100 if (flags
& T_EXPEDITED
)
101 tsdu_limit
= tiptr
->ti_etsdusize
;
104 tsdu_limit
= tiptr
->ti_tsdusize
;
108 * nbytes is the sum of the bytecounts in the tiov vector
109 * A value larger than INT_MAX is truncated to INT_MAX by
110 * _t_bytecount_upto_intmax()
112 nbytes
= _t_bytecount_upto_intmax(tiov
, tiovcount
);
114 if ((tsdu_limit
> 0) && /* limit meaningful and ... */
115 (nbytes
> (uint32_t)tsdu_limit
)) {
117 sig_mutex_unlock(&tiptr
->ti_lock
);
122 * Check for incoming disconnect only. XNS Issue 5 makes it optional
123 * to check for incoming orderly release
125 lookevent
= _t_look_locked(fd
, tiptr
, 0, api_semantics
);
128 sig_mutex_unlock(&tiptr
->ti_lock
);
132 if (lookevent
== T_DISCONNECT
) {
134 sig_mutex_unlock(&tiptr
->ti_lock
);
138 /* sending zero length data when not allowed */
139 if (nbytes
== 0 && !(tiptr
->ti_prov_flag
& (SENDZERO
|OLD_SENDZERO
))) {
141 sig_mutex_unlock(&tiptr
->ti_lock
);
145 doputmsg
= (tiptr
->ti_tsdusize
!= 0) || (flags
& T_EXPEDITED
);
149 * Initialize ctlbuf for use in sending/receiving control part
152 ctlbuf
.maxlen
= (int)sizeof (struct T_data_req
);
153 ctlbuf
.len
= (int)sizeof (struct T_data_req
);
154 ctlbuf
.buf
= (char *)&datareq
;
156 band
= TI_NORMAL
; /* band 0 */
157 if (flags
& T_EXPEDITED
) {
158 datareq
.PRIM_type
= T_EXDATA_REQ
;
159 if (!(tiptr
->ti_prov_flag
& EXPINLINE
))
160 band
= TI_EXPEDITED
; /* band > 0 */
162 datareq
.PRIM_type
= T_DATA_REQ
;
164 * Allocate a databuffer into which we will gather the
165 * input vector data, and make a call to putmsg(). We
166 * do this since we don't have the equivalent of a putmsgv()
169 if ((dataptr
= malloc((size_t)nbytes
)) == NULL
) {
171 sig_mutex_unlock(&tiptr
->ti_lock
);
174 return (-1); /* error */
177 * Gather the input buffers, into the single linear
178 * buffer allocated above, while taking care to see
179 * that no more than INT_MAX bytes will be copied.
181 _t_gather(dataptr
, tiov
, tiovcount
);
182 curptr
= dataptr
; /* Initialize for subsequent use */
189 bytes_remaining
= nbytes
;
191 * Calls to send data (write or putmsg) can potentially
192 * block, for MT case, we drop the lock and enable signals here
193 * and acquire it back
195 sig_mutex_unlock(&tiptr
->ti_lock
);
198 bytes_to_send
= bytes_remaining
;
201 * transport provider supports TSDU concept
202 * (unlike TCP) or it is expedited data.
203 * In this case do the fragmentation
205 if (bytes_to_send
> (unsigned int)tiptr
->ti_maxpsz
) {
206 datareq
.MORE_flag
= 1;
207 bytes_to_send
= (unsigned int)tiptr
->ti_maxpsz
;
210 datareq
.MORE_flag
= 1;
212 datareq
.MORE_flag
= 0;
214 databuf
.maxlen
= bytes_to_send
;
215 databuf
.len
= bytes_to_send
;
216 databuf
.buf
= curptr
;
217 retval
= putpmsg(fd
, &ctlbuf
, &databuf
, band
, MSG_BAND
);
219 bytes_sent
= bytes_to_send
;
220 curptr
= curptr
+ bytes_sent
;
224 * transport provider does *not* support TSDU concept
225 * (e.g. TCP) and it is not expedited data. A
226 * perf. optimization is used. Note: the T_MORE
227 * flag is ignored here even if set by the user.
230 * The first time, setup the tiovec for doing a writev
231 * call. We assume that T_IOV_MAX <= IOV_MAX.
232 * Since writev may return a partial count, we need
233 * the loop. After the first time, we just adjust
234 * the iov vector to not include the already
239 _t_copy_tiov_to_iov(tiov
, tiovcount
, iov
,
243 * bytes_sent - value set below in the previous
244 * iteration of the loop is used now.
246 _t_adjust_iov(bytes_sent
, iov
, &iovcount
);
248 retval
= (int)writev(fd
, iov
, iovcount
);
250 /* Amount that was actually sent */
256 if (nbytes
== bytes_remaining
) {
258 * Error on *first* putmsg/write attempt.
259 * Return appropriate error
266 return (-1); /* return error */
269 * Not the first putmsg/write
270 * [ partial completion of t_snd() case.
272 * Error on putmsg/write attempt but
273 * some data was transmitted so don't
274 * return error. Don't attempt to
275 * send more (break from loop) but
280 bytes_remaining
= bytes_remaining
- bytes_sent
;
281 } while (bytes_remaining
!= 0);
284 _T_TX_NEXTSTATE(T_SND
, tiptr
, "t_snd: invalid state event T_SND");
285 return (nbytes
- bytes_remaining
);