xref: /illumos-gate/usr/src/lib/libnsl/nsl/t_look.c (revision 61961e0f)
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 2005 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 
45 int
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  */
75 int
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