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 (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
24/*	  All Rights Reserved  	*/
25
26/*
27 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
28 * Use is subject to license terms.
29 */
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33#include "mt.h"
34#include <errno.h>
35#include <unistd.h>
36#include <sys/stream.h>
37#include <stropts.h>
38#define	_SUN_TPI_VERSION 2
39#include <sys/tihdr.h>
40#include <sys/timod.h>
41#include <xti.h>
42#include <assert.h>
43#include "tx.h"
44
45int
46_tx_look(int fd, int api_semantics)
47{
48	int state;
49	int sv_errno;
50	int do_expinline_peek;	 /* unusual XTI specific processing */
51	struct _ti_user *tiptr;
52
53	if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL)
54		return (-1);
55	sig_mutex_lock(&tiptr->ti_lock);
56
57	if (_T_IS_XTI(api_semantics))
58		do_expinline_peek = 1;
59	else
60		do_expinline_peek = 0;
61	state = _t_look_locked(fd, tiptr, do_expinline_peek, api_semantics);
62
63	sv_errno = errno;
64
65	sig_mutex_unlock(&tiptr->ti_lock);
66	errno = sv_errno;
67	return (state);
68}
69
70/*
71 * _t_look_locked() assumes tiptr->ti_lock lock is already held and signals
72 * already blocked in MT case.
73 * Intended for use by other TLI routines only.
74 */
75int
76_t_look_locked(
77	int fd,
78	struct _ti_user *tiptr,
79	int do_expinline_peek,
80	int api_semantics
81)
82{
83	struct strpeek strpeek;
84	int retval;
85	union T_primitives *pptr;
86	t_scalar_t type;
87	t_scalar_t ctltype;
88
89	assert(MUTEX_HELD(&tiptr->ti_lock));
90
91#ifdef notyet
92	if (_T_IS_XTI(api_semantics)) {
93		/*
94		 * XTI requires the strange T_GODATA and T_GOEXDATA
95		 * events which are almost brain-damaged but thankfully
96		 * not tested. Anyone feeling the need for those should
97		 * consider the need for using non-blocking endpoint.
98		 * Probably introduced at the behest of some weird-os
99		 * vendor which did not understand the non-blocking endpoint
100		 * option.
101		 * We choose not to implment these mis-features.
102		 * Here is the plan-of-action (POA)if we are ever forced
103		 * to implement these.
104		 * - When returning TFLOW set state to indicate if it was
105		 *   a normal or expedited data send attempt.
106		 * - In routines that set TFLOW, clear the above set state
107		 *   on each entry/reentry
108		 * - In this routine, if that state flag is set,
109		 * do a I_CANPUT on appropriate band to to see if it
110		 * is writeable. If that indicates that the band is
111		 * writeable, return T_GODATA or T_GOEXDATA event.
112		 *
113		 * Actions are also influenced by whether T_EXDATA_REQ stays
114		 * band 1 or goes to band 0 if EXPINLINE is set
115		 *
116		 * We will also need to sort out if "write side" events
117		 * (such as T_GODATA/T_GOEXDATA) take precedence over
118		 * all other events (all read side) or not.
119		 */
120	}
121#endif /* notyet */
122
123	strpeek.ctlbuf.maxlen = (int)sizeof (ctltype);
124	strpeek.ctlbuf.len = 0;
125	strpeek.ctlbuf.buf = (char *)&ctltype;
126	strpeek.databuf.maxlen = 0;
127	strpeek.databuf.len = 0;
128	strpeek.databuf.buf = NULL;
129	strpeek.flags = 0;
130
131	do {
132		retval = ioctl(fd, I_PEEK, &strpeek);
133	} while (retval < 0 && errno == EINTR);
134
135	if (retval < 0) {
136		if (_T_IS_TLI(api_semantics)) {
137			/*
138			 * This return of T_ERROR event is ancient
139			 * SVR3 TLI semantics and not documented for
140			 * current SVR4 TLI interface.
141			 * Fixing this will impact some apps
142			 * (e.g. nfsd,lockd) in ON consolidation
143			 * so they need to be fixed first before TLI
144			 * can be fixed.
145			 * XXX Should we never fix this because it might
146			 * break apps in field ?
147			 */
148			return (T_ERROR);
149		}
150		/*
151		 * XTI semantics (also identical to documented,
152		 * but not implemented TLI semantics).
153		 */
154		t_errno = TSYSERR;
155		return (-1);
156	}
157
158	/*
159	 * if something there and cntl part also there
160	 */
161	if ((tiptr->ti_lookcnt > 0) ||
162	((retval > 0) && (strpeek.ctlbuf.len >= (int)sizeof (t_scalar_t)))) {
163		/* LINTED pointer cast */
164		pptr = (union T_primitives *)strpeek.ctlbuf.buf;
165		if (tiptr->ti_lookcnt > 0) {
166			/* LINTED pointer cast */
167			type = *((t_scalar_t *)tiptr->ti_lookbufs.tl_lookcbuf);
168			/*
169			 * If message on stream head is a T_DISCON_IND, that
170			 * has priority over a T_ORDREL_IND in the look
171			 * buffer.
172			 * (This assumes that T_ORDREL_IND can only be in the
173			 * first look buffer in the list)
174			 */
175			if ((type == T_ORDREL_IND) && retval &&
176			    (pptr->type == T_DISCON_IND)) {
177				type = pptr->type;
178				/*
179				 * Blow away T_ORDREL_IND
180				 */
181				_t_free_looklist_head(tiptr);
182			}
183		} else
184			type = pptr->type;
185
186		switch (type) {
187
188		case T_CONN_IND:
189			return (T_LISTEN);
190
191		case T_CONN_CON:
192			return (T_CONNECT);
193
194		case T_DISCON_IND:
195			return (T_DISCONNECT);
196
197		case T_DATA_IND: {
198			int event = T_DATA;
199			int retval, exp_on_q;
200
201			if (do_expinline_peek &&
202			    (tiptr->ti_prov_flag & EXPINLINE)) {
203				assert(_T_IS_XTI(api_semantics));
204				retval = _t_expinline_queued(fd, &exp_on_q);
205				if (retval < 0) {
206					t_errno = TSYSERR;
207					return (-1);
208				}
209				if (exp_on_q)
210					event = T_EXDATA;
211			}
212			return (event);
213		}
214
215		case T_UNITDATA_IND:
216			return (T_DATA);
217
218		case T_EXDATA_IND:
219			return (T_EXDATA);
220
221		case T_UDERROR_IND:
222			return (T_UDERR);
223
224		case T_ORDREL_IND:
225			return (T_ORDREL);
226
227		default:
228			t_errno = TSYSERR;
229			errno = EPROTO;
230			return (-1);
231		}
232	}
233
234	/*
235	 * if something there put no control part
236	 * it must be data on the stream head.
237	 */
238	if ((retval > 0) && (strpeek.ctlbuf.len <= 0)) {
239		int event = T_DATA;
240		int retval, exp_on_q;
241
242		if (do_expinline_peek &&
243		    (tiptr->ti_prov_flag & EXPINLINE)) {
244			assert(_T_IS_XTI(api_semantics));
245			retval = _t_expinline_queued(fd, &exp_on_q);
246			if (retval < 0)
247				return (-1);
248			if (exp_on_q)
249				event = T_EXDATA;
250		}
251		return (event);
252	}
253
254	/*
255	 * if msg there and control
256	 * part not large enough to determine type?
257	 * it must be illegal TLI message
258	 */
259	if ((retval > 0) && (strpeek.ctlbuf.len > 0)) {
260		t_errno = TSYSERR;
261		errno = EPROTO;
262		return (-1);
263	}
264	return (0);
265}
266