xref: /illumos-gate/usr/src/lib/libnsl/nsl/t_rcvudata.c (revision 1da57d55)
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 /*
32  * t_rcvudata.c and t_rcvvudata.c are very similar and contain common code.
33  * Any changes to either of them should be reviewed to see whether they
34  * are applicable to the other file.
35  */
36 #include "mt.h"
37 #include <string.h>
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <stropts.h>
41 #include <sys/stream.h>
42 #define	_SUN_TPI_VERSION 2
43 #include <sys/tihdr.h>
44 #include <sys/timod.h>
45 #include <xti.h>
46 #include <syslog.h>
47 #include "tx.h"
48 
49 
50 int
_tx_rcvudata(int fd,struct t_unitdata * unitdata,int * flags,int api_semantics)51 _tx_rcvudata(
52 	int fd,
53 	struct t_unitdata *unitdata,
54 	int *flags,
55 	int api_semantics
56 )
57 {
58 	struct strbuf ctlbuf;
59 	int retval;
60 	union T_primitives *pptr;
61 	struct _ti_user *tiptr;
62 	int sv_errno;
63 	int didalloc;
64 	int flg = 0;
65 
66 	if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL)
67 		return (-1);
68 	sig_mutex_lock(&tiptr->ti_lock);
69 
70 	if (tiptr->ti_servtype != T_CLTS) {
71 		t_errno = TNOTSUPPORT;
72 		sig_mutex_unlock(&tiptr->ti_lock);
73 		return (-1);
74 	}
75 
76 	if (_T_IS_XTI(api_semantics)) {
77 		/*
78 		 * User level state verification only done for XTI
79 		 * because doing for TLI may break existing applications
80 		 */
81 		if (tiptr->ti_state != T_IDLE) {
82 			t_errno = TOUTSTATE;
83 			sig_mutex_unlock(&tiptr->ti_lock);
84 			return (-1);
85 		}
86 	}
87 
88 
89 	/*
90 	 * check if there is something in look buffer
91 	 */
92 	if (tiptr->ti_lookcnt > 0) {
93 		sig_mutex_unlock(&tiptr->ti_lock);
94 		t_errno = TLOOK;
95 		return (-1);
96 	}
97 
98 	/*
99 	 * Acquire ctlbuf for use in sending/receiving control part
100 	 * of the message.
101 	 */
102 	if (_t_acquire_ctlbuf(tiptr, &ctlbuf, &didalloc) < 0) {
103 		sv_errno = errno;
104 		sig_mutex_unlock(&tiptr->ti_lock);
105 		errno = sv_errno;
106 		return (-1);
107 	}
108 
109 	*flags = 0;
110 
111 	/*
112 	 * This is a call that may block indefinitely so we drop the
113 	 * lock and allow signals in MT case here and reacquire it.
114 	 * Error case should roll back state changes done above
115 	 * (happens to be no state change here)
116 	 */
117 	sig_mutex_unlock(&tiptr->ti_lock);
118 	if ((retval = getmsg(fd, &ctlbuf, (struct strbuf *)&unitdata->udata,
119 				&flg)) < 0) {
120 		if (errno == EAGAIN)
121 			t_errno = TNODATA;
122 		else
123 			t_errno = TSYSERR;
124 		sv_errno = errno;
125 		sig_mutex_lock(&tiptr->ti_lock);
126 		errno = sv_errno;
127 		goto err_out;
128 	}
129 	sig_mutex_lock(&tiptr->ti_lock);
130 
131 	if (((struct strbuf *)&unitdata->udata)->len == -1)
132 		unitdata->udata.len = 0;
133 
134 	/*
135 	 * is there control piece with data?
136 	 */
137 	if (ctlbuf.len > 0) {
138 		if (ctlbuf.len < (int)sizeof (t_scalar_t)) {
139 			unitdata->udata.len = 0;
140 			t_errno = TSYSERR;
141 			errno = EPROTO;
142 			goto err_out;
143 		}
144 
145 		/* LINTED pointer cast */
146 		pptr = (union T_primitives *)ctlbuf.buf;
147 
148 		switch (pptr->type) {
149 
150 		case T_UNITDATA_IND:
151 			if ((ctlbuf.len <
152 			    (int)sizeof (struct T_unitdata_ind)) ||
153 			    (pptr->unitdata_ind.OPT_length &&
154 			    (ctlbuf.len < (int)(pptr->unitdata_ind.OPT_length
155 			    + pptr->unitdata_ind.OPT_offset)))) {
156 				t_errno = TSYSERR;
157 				unitdata->udata.len = 0;
158 				errno = EPROTO;
159 				goto err_out;
160 			}
161 
162 			if (_T_IS_TLI(api_semantics) ||
163 			    unitdata->addr.maxlen > 0) {
164 				if (TLEN_GT_NLEN(pptr->unitdata_ind.SRC_length,
165 				    unitdata->addr.maxlen)) {
166 					t_errno = TBUFOVFLW;
167 					unitdata->udata.len = 0;
168 					goto err_out;
169 				}
170 				(void) memcpy(unitdata->addr.buf,
171 				    ctlbuf.buf + pptr->unitdata_ind.SRC_offset,
172 				    (size_t)pptr->unitdata_ind.SRC_length);
173 				unitdata->addr.len =
174 				    pptr->unitdata_ind.SRC_length;
175 			}
176 			if (_T_IS_TLI(api_semantics) ||
177 			    unitdata->opt.maxlen > 0) {
178 				if (TLEN_GT_NLEN(pptr->unitdata_ind.OPT_length,
179 				    unitdata->opt.maxlen)) {
180 					t_errno = TBUFOVFLW;
181 					unitdata->udata.len = 0;
182 					goto err_out;
183 				}
184 				(void) memcpy(unitdata->opt.buf, ctlbuf.buf +
185 				    pptr->unitdata_ind.OPT_offset,
186 				    (size_t)pptr->unitdata_ind.OPT_length);
187 				unitdata->opt.len =
188 					pptr->unitdata_ind.OPT_length;
189 			}
190 			if (retval & MOREDATA)
191 				*flags |= T_MORE;
192 			/*
193 			 * No state changes happens on T_RCVUDATA
194 			 * event (NOOP). We do it only to log errors.
195 			 */
196 			_T_TX_NEXTSTATE(T_RCVUDATA, tiptr,
197 			    "t_rcvudata: invalid state event T_RCVUDATA");
198 
199 			if (didalloc)
200 				free(ctlbuf.buf);
201 			else
202 				tiptr->ti_ctlbuf = ctlbuf.buf;
203 
204 			sig_mutex_unlock(&tiptr->ti_lock);
205 			return (0);
206 
207 		case T_UDERROR_IND:
208 			if (_t_register_lookevent(tiptr, 0, 0, ctlbuf.buf,
209 				ctlbuf.len) < 0) {
210 				t_errno = TSYSERR;
211 				errno = ENOMEM;
212 				goto err_out;
213 			}
214 			unitdata->udata.len = 0;
215 			t_errno = TLOOK;
216 			goto err_out;
217 
218 		default:
219 			break;
220 		}
221 
222 		t_errno = TSYSERR;
223 		errno = EPROTO;
224 		goto err_out;
225 
226 	} else {		/* else part of "if (ctlbuf.len > 0)" */
227 		unitdata->addr.len = 0;
228 		unitdata->opt.len = 0;
229 		/*
230 		 * only data in message no control piece
231 		 */
232 		if (retval & MOREDATA)
233 			*flags = T_MORE;
234 		/*
235 		 * No state transition occurs on
236 		 * event T_RCVUDATA. We do it only to
237 		 * log errors.
238 		 */
239 		_T_TX_NEXTSTATE(T_RCVUDATA, tiptr,
240 		    "t_rcvudata: invalid state event T_RCVUDATA");
241 		if (didalloc)
242 			free(ctlbuf.buf);
243 		else
244 			tiptr->ti_ctlbuf = ctlbuf.buf;
245 		sig_mutex_unlock(&tiptr->ti_lock);
246 		return (0);
247 	}
248 	/* NOTREACHED */
249 err_out:
250 	sv_errno = errno;
251 	if (didalloc)
252 		free(ctlbuf.buf);
253 	else
254 		tiptr->ti_ctlbuf = ctlbuf.buf;
255 	sig_mutex_unlock(&tiptr->ti_lock);
256 	errno = sv_errno;
257 	return (-1);
258 }
259