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
50int
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 */
259err_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