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_rcvrel.c and t_rcvreldata.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 <stdlib.h>
37#include <errno.h>
38#include <stropts.h>
39#include <sys/stream.h>
40#define	_SUN_TPI_VERSION 2
41#include <sys/tihdr.h>
42#include <sys/timod.h>
43#include <xti.h>
44#include <signal.h>
45#include <syslog.h>
46#include <assert.h>
47#include "tx.h"
48
49/* ARGSUSED */
50int
51_tx_rcvreldata(int fd, struct t_discon *discon, int api_semantics)
52{
53	struct strbuf ctlbuf;
54	struct strbuf databuf;
55	int retval;
56	union T_primitives *pptr;
57	struct _ti_user *tiptr;
58	int sv_errno;
59	int didalloc, didralloc;
60
61	int flg = 0;
62
63
64	assert(api_semantics == TX_XTI_XNS5_API);
65	if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == 0)
66		return (-1);
67	sig_mutex_lock(&tiptr->ti_lock);
68
69	if (tiptr->ti_servtype != T_COTS_ORD) {
70		t_errno = TNOTSUPPORT;
71		sig_mutex_unlock(&tiptr->ti_lock);
72		return (-1);
73	}
74
75	if (!(tiptr->ti_state == T_DATAXFER ||
76	    tiptr->ti_state == T_OUTREL)) {
77		t_errno = TOUTSTATE;
78		sig_mutex_unlock(&tiptr->ti_lock);
79		return (-1);
80	}
81
82	if ((retval = _t_look_locked(fd, tiptr, 0, api_semantics)) < 0) {
83		sv_errno = errno;
84		sig_mutex_unlock(&tiptr->ti_lock);
85		errno = sv_errno;
86		return (-1);
87	}
88
89	if (retval == T_DISCONNECT) {
90		/*
91		 * This ensures preference to T_DISCON_IND which is
92		 * the design model for TPI
93		 */
94		t_errno = TLOOK;
95		sig_mutex_unlock(&tiptr->ti_lock);
96		return (-1);
97	}
98
99	/*
100	 * Someday there could be transport providers that support T_ORDRELDATA
101	 * Until then this function behaves the same as t_rcvrel()
102	 * Note: Currently only mOSI ("minimal OSI") provider is specified
103	 * to use T_ORDRELDATA so probability of needing it is minimal.
104	 */
105
106	if ((tiptr->ti_lookcnt > 0) &&
107	    /* LINTED pointer cast */
108	    (*((t_scalar_t *)tiptr->ti_lookbufs.tl_lookcbuf) == T_ORDREL_IND)) {
109		/*
110		 * Current look buffer event is T_ORDREL_IND.
111		 * Remove it from look buffer event list.
112		 */
113		_t_free_looklist_head(tiptr);
114		_T_TX_NEXTSTATE(T_RCVREL, tiptr,
115			"t_rcvreldata: invalid state event T_RCVREL");
116		sig_mutex_unlock(&tiptr->ti_lock);
117		return (0);
118	} else {
119		if (retval != T_ORDREL) {
120			t_errno = TNOREL;
121			sig_mutex_unlock(&tiptr->ti_lock);
122			return (-1);
123		}
124	}
125
126	/*
127	 * get ordrel off read queue.
128	 * use ctl and rcv buffers
129	 *
130	 * Acquire ctlbuf for use in sending/receiving control part
131	 * of the message.
132	 */
133	if (_t_acquire_ctlbuf(tiptr, &ctlbuf, &didalloc) < 0) {
134		sv_errno = errno;
135		sig_mutex_unlock(&tiptr->ti_lock);
136		errno = sv_errno;
137		return (-1);
138	}
139
140	/*
141	 * Acquire databuf for use in sending/receiving data part
142	 */
143	if (_t_acquire_databuf(tiptr, &databuf, &didralloc) < 0) {
144		sv_errno = errno;
145		if (didalloc)
146			free(ctlbuf.buf);
147		else
148			tiptr->ti_ctlbuf = ctlbuf.buf;
149		sig_mutex_unlock(&tiptr->ti_lock);
150		errno = sv_errno;
151		return (-1);
152	}
153
154	/*
155	 * Since we have verified above that an orderly release event
156	 * is pending on this endpoint, we assume that this getmsg()
157	 * cannot block forever.
158	 */
159	do {
160		retval = getmsg(fd, &ctlbuf, &databuf, &flg);
161	} while (retval < 0 && errno == EINTR);
162
163	if (retval < 0) {
164		t_errno = TSYSERR;
165		goto err_out;
166	}
167
168	/*
169	 * did I get entire message?
170	 */
171	if (retval > 0) {
172		t_errno = TSYSERR;
173		errno = EIO;
174		goto err_out;
175	}
176	/* LINTED pointer cast */
177	pptr = (union T_primitives *)ctlbuf.buf;
178
179	if (ctlbuf.len < (int)sizeof (struct T_ordrel_ind)) {
180		t_errno = TSYSERR;
181		errno = EPROTO;
182		goto err_out;
183	}
184	if (pptr->type != T_ORDREL_IND) {
185		if (pptr->type == T_DISCON_IND) {
186			/*
187			 * T_DISCON_IND gets priority following
188			 * TPI design philosphy.
189			 *
190			 * Add it to the events in the "look buffer"
191			 * list of events. This routine may defer signals.
192			 */
193			if (_t_register_lookevent(tiptr, databuf.buf,
194						databuf.len, ctlbuf.buf,
195						ctlbuf.len) < 0) {
196				t_errno = TSYSERR;
197				errno = ENOMEM;
198				goto err_out;
199			}
200			t_errno = TLOOK;
201			goto err_out;
202		} else {
203			t_errno = TSYSERR;
204			errno = EPROTO;
205			goto err_out;
206		}
207	}
208
209	_T_TX_NEXTSTATE(T_RCVREL, tiptr,
210		"t_rcvreldata: invalid state event T_RCVREL");
211
212	if (didalloc)
213		free(ctlbuf.buf);
214	else
215		tiptr->ti_ctlbuf = ctlbuf.buf;
216	if (didralloc)
217		free(databuf.buf);
218	else
219		tiptr->ti_rcvbuf = databuf.buf;
220	sig_mutex_unlock(&tiptr->ti_lock);
221	return (0);
222
223err_out:
224	sv_errno = errno;
225
226	if (didalloc)
227		free(ctlbuf.buf);
228	else
229		tiptr->ti_ctlbuf = ctlbuf.buf;
230	if (didralloc)
231		free(databuf.buf);
232	else
233		tiptr->ti_rcvbuf = databuf.buf;
234	sig_mutex_unlock(&tiptr->ti_lock);
235	errno = sv_errno;
236	return (-1);
237}
238