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