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
_tx_rcvvudata(int fd,struct t_unitdata * unitdata,struct t_iovec * tiov,unsigned int tiovcount,int * flags,int api_semantics)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