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