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