xref: /titanic_50/usr/src/lib/libnsl/nsl/t_rcvudata.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright 1993-2003 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.5 */
33 
34 /*
35  * t_rcvudata.c and t_rcvvudata.c are very similar and contain common code.
36  * Any changes to either of them should be reviewed to see whether they
37  * are applicable to the other file.
38  */
39 #include "mt.h"
40 #include <rpc/trace.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <errno.h>
44 #include <stropts.h>
45 #include <sys/stream.h>
46 #define	_SUN_TPI_VERSION 2
47 #include <sys/tihdr.h>
48 #include <sys/timod.h>
49 #include <xti.h>
50 #include <syslog.h>
51 #include "tx.h"
52 
53 
54 int
55 _tx_rcvudata(
56 	int fd,
57 	struct t_unitdata *unitdata,
58 	int *flags,
59 	int api_semantics
60 )
61 {
62 	struct strbuf ctlbuf;
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 
70 	trace2(TR_t_rcvudata, 0, fd);
71 	if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL) {
72 		sv_errno = errno;
73 		trace2(TR_t_rcvudata, 1, fd);
74 		errno = sv_errno;
75 		return (-1);
76 	}
77 	sig_mutex_lock(&tiptr->ti_lock);
78 
79 	if (tiptr->ti_servtype != T_CLTS) {
80 		t_errno = TNOTSUPPORT;
81 		sig_mutex_unlock(&tiptr->ti_lock);
82 		trace2(TR_t_rcvudata, 1, fd);
83 		return (-1);
84 	}
85 
86 	if (_T_IS_XTI(api_semantics)) {
87 		/*
88 		 * User level state verification only done for XTI
89 		 * because doing for TLI may break existing applications
90 		 */
91 		if (tiptr->ti_state != T_IDLE) {
92 			t_errno = TOUTSTATE;
93 			sig_mutex_unlock(&tiptr->ti_lock);
94 			trace2(TR_t_rcvudata, 1, fd);
95 			return (-1);
96 		}
97 	}
98 
99 
100 	/*
101 	 * check if there is something in look buffer
102 	 */
103 	if (tiptr->ti_lookcnt > 0) {
104 		sig_mutex_unlock(&tiptr->ti_lock);
105 		trace2(TR_t_rcvudata, 1, fd);
106 		t_errno = TLOOK;
107 		return (-1);
108 	}
109 
110 	/*
111 	 * Acquire ctlbuf for use in sending/receiving control part
112 	 * of the message.
113 	 */
114 	if (_t_acquire_ctlbuf(tiptr, &ctlbuf, &didalloc) < 0) {
115 		sv_errno = errno;
116 		sig_mutex_unlock(&tiptr->ti_lock);
117 		trace2(TR_t_rcvudata, 1, fd);
118 		errno = sv_errno;
119 		return (-1);
120 	}
121 
122 	*flags = 0;
123 
124 	/*
125 	 * This is a call that may block indefinitely so we drop the
126 	 * lock and allow signals in MT case here and reacquire it.
127 	 * Error case should roll back state changes done above
128 	 * (happens to be no state change here)
129 	 */
130 	sig_mutex_unlock(&tiptr->ti_lock);
131 	if ((retval = getmsg(fd, &ctlbuf, (struct strbuf *)&unitdata->udata,
132 				&flg)) < 0) {
133 		if (errno == EAGAIN)
134 			t_errno = TNODATA;
135 		else
136 			t_errno = TSYSERR;
137 		sv_errno = errno;
138 		sig_mutex_lock(&tiptr->ti_lock);
139 		errno = sv_errno;
140 		goto err_out;
141 	}
142 	sig_mutex_lock(&tiptr->ti_lock);
143 
144 	if (unitdata->udata.len == -1) unitdata->udata.len = 0;
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 			unitdata->udata.len = 0;
152 			t_errno = TSYSERR;
153 			errno = EPROTO;
154 			goto err_out;
155 		}
156 
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 				unitdata->udata.len = 0;
169 				errno = EPROTO;
170 				goto err_out;
171 			}
172 
173 			if (_T_IS_TLI(api_semantics) ||
174 			    unitdata->addr.maxlen > 0) {
175 				if (TLEN_GT_NLEN(pptr->unitdata_ind.SRC_length,
176 				    unitdata->addr.maxlen)) {
177 					t_errno = TBUFOVFLW;
178 					unitdata->udata.len = 0;
179 					goto err_out;
180 				}
181 				(void) memcpy(unitdata->addr.buf,
182 				    ctlbuf.buf + pptr->unitdata_ind.SRC_offset,
183 				    (size_t)pptr->unitdata_ind.SRC_length);
184 				unitdata->addr.len =
185 				    pptr->unitdata_ind.SRC_length;
186 			}
187 			if (_T_IS_TLI(api_semantics) ||
188 			    unitdata->opt.maxlen > 0) {
189 				if (TLEN_GT_NLEN(pptr->unitdata_ind.OPT_length,
190 				    unitdata->opt.maxlen)) {
191 					t_errno = TBUFOVFLW;
192 					unitdata->udata.len = 0;
193 					goto err_out;
194 				}
195 				(void) memcpy(unitdata->opt.buf, ctlbuf.buf +
196 				    pptr->unitdata_ind.OPT_offset,
197 				    (size_t)pptr->unitdata_ind.OPT_length);
198 				unitdata->opt.len =
199 					pptr->unitdata_ind.OPT_length;
200 			}
201 			if (retval & MOREDATA)
202 				*flags |= T_MORE;
203 			/*
204 			 * No state changes happens on T_RCVUDATA
205 			 * event (NOOP). We do it only to log errors.
206 			 */
207 			_T_TX_NEXTSTATE(T_RCVUDATA, tiptr,
208 			    "t_rcvudata: invalid state event T_RCVUDATA");
209 
210 			if (didalloc)
211 				free(ctlbuf.buf);
212 			else
213 				tiptr->ti_ctlbuf = ctlbuf.buf;
214 
215 			sig_mutex_unlock(&tiptr->ti_lock);
216 			trace2(TR_t_rcvudata, 1, fd);
217 			return (0);
218 
219 		case T_UDERROR_IND:
220 			if (_t_register_lookevent(tiptr, 0, 0, ctlbuf.buf,
221 				ctlbuf.len) < 0) {
222 				t_errno = TSYSERR;
223 				errno = ENOMEM;
224 				goto err_out;
225 			}
226 			unitdata->udata.len = 0;
227 			t_errno = TLOOK;
228 			goto err_out;
229 
230 		default:
231 			break;
232 		}
233 
234 		t_errno = TSYSERR;
235 		errno = EPROTO;
236 		goto err_out;
237 
238 	} else {		/* else part of "if (ctlbuf.len > 0)" */
239 		unitdata->addr.len = 0;
240 		unitdata->opt.len = 0;
241 		/*
242 		 * only data in message no control piece
243 		 */
244 		if (retval & MOREDATA)
245 			*flags = T_MORE;
246 		/*
247 		 * No state transition occurs on
248 		 * event T_RCVUDATA. We do it only to
249 		 * log errors.
250 		 */
251 		_T_TX_NEXTSTATE(T_RCVUDATA, tiptr,
252 		    "t_rcvudata: invalid state event T_RCVUDATA");
253 		if (didalloc)
254 			free(ctlbuf.buf);
255 		else
256 			tiptr->ti_ctlbuf = ctlbuf.buf;
257 		sig_mutex_unlock(&tiptr->ti_lock);
258 		trace2(TR_t_rcvudata, 1, fd);
259 		return (0);
260 	}
261 	/* NOTREACHED */
262 err_out:
263 	sv_errno = errno;
264 	if (didalloc)
265 		free(ctlbuf.buf);
266 	else
267 		tiptr->ti_ctlbuf = ctlbuf.buf;
268 	sig_mutex_unlock(&tiptr->ti_lock);
269 	trace2(TR_t_rcvudata, 1, fd);
270 	errno = sv_errno;
271 	return (-1);
272 }
273