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