xref: /illumos-gate/usr/src/lib/libnsl/nsl/_conn_util.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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include "mt.h"
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <rpc/trace.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <stdlib.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 <signal.h>
47 #include <assert.h>
48 #include "tx.h"
49 
50 
51 /*
52  * Snd_conn_req - send connect request message to transport provider.
53  * All signals for the caller are blocked during the call to simplify design.
54  * (This is OK for a bounded amount of time this routine is expected to
55  * execute).  Also, assumes tiptr->ti_lock is held.
56  */
57 int
58 _t_snd_conn_req(
59 	struct _ti_user *tiptr,
60 	const struct t_call *call,
61 	struct strbuf *ctlbufp)
62 {
63 	struct T_conn_req *creq;
64 	int size, sv_errno;
65 	int fd;
66 
67 	trace2(TR__t_snd_conn_req, 0, fd);
68 	assert(MUTEX_HELD(&tiptr->ti_lock));
69 	fd = tiptr->ti_fd;
70 
71 	if (tiptr->ti_servtype == T_CLTS) {
72 		t_errno = TNOTSUPPORT;
73 		trace2(TR__t_snd_conn_req, 1, fd);
74 		return (-1);
75 	}
76 
77 	if (_t_is_event(fd, tiptr) < 0) {
78 		sv_errno = errno;
79 		trace2(TR__t_snd_conn_req, 1, fd);
80 		errno = sv_errno;
81 		return (-1);
82 	}
83 
84 	creq = (struct T_conn_req *)ctlbufp->buf;
85 	creq->PRIM_type = T_CONN_REQ;
86 	creq->DEST_length = call->addr.len;
87 	creq->DEST_offset = 0;
88 	creq->OPT_length = call->opt.len;
89 	creq->OPT_offset = 0;
90 	size = (int)sizeof (struct T_conn_req); /* size without any buffers */
91 
92 	if (call->addr.len) {
93 		if (_t_aligned_copy(ctlbufp, call->addr.len, size,
94 		    call->addr.buf, &creq->DEST_offset) < 0) {
95 			/*
96 			 * Aligned copy will overflow buffer allocated based
97 			 * based on transport maximum address size.
98 			 * return error.
99 			 */
100 			t_errno = TBADADDR;
101 			trace2(TR__t_snd_conn_req, 1, fd);
102 			return (-1);
103 		}
104 		size = creq->DEST_offset + creq->DEST_length;
105 	}
106 	if (call->opt.len) {
107 		if (_t_aligned_copy(ctlbufp, call->opt.len, size,
108 		    call->opt.buf, &creq->OPT_offset) < 0) {
109 			/*
110 			 * Aligned copy will overflow buffer allocated based
111 			 * on maximum option size in transport.
112 			 * return error.
113 			 */
114 			t_errno = TBADOPT;
115 			trace2(TR__t_snd_conn_req, 1, fd);
116 			return (-1);
117 		}
118 		size = creq->OPT_offset + creq->OPT_length;
119 	}
120 	if (call->udata.len) {
121 		if ((tiptr->ti_cdatasize == T_INVALID /* -2 */) ||
122 		    ((tiptr->ti_cdatasize != T_INFINITE /* -1 */) &&
123 			(call->udata.len > (uint32_t)tiptr->ti_cdatasize))) {
124 			/*
125 			 * user data not valid with connect or it
126 			 * exceeds the limits specified by the transport
127 			 * provider.
128 			 */
129 			t_errno = TBADDATA;
130 			trace2(TR__t_snd_conn_req, 1, fd);
131 			return (-1);
132 		}
133 	}
134 
135 	ctlbufp->len = size;
136 
137 	/*
138 	 * Assumes signals are blocked so putmsg() will not block
139 	 * indefinitely
140 	 */
141 	if (putmsg(fd, ctlbufp,
142 	    (struct strbuf *)(call->udata.len? &call->udata: NULL), 0) < 0) {
143 		sv_errno = errno;
144 		t_errno = TSYSERR;
145 		trace2(TR__t_snd_conn_req, 1, fd);
146 		errno = sv_errno;
147 		return (-1);
148 	}
149 
150 	if (_t_is_ok(fd, tiptr, T_CONN_REQ) < 0) {
151 		sv_errno = errno;
152 		trace2(TR__t_snd_conn_req, 1, fd);
153 		errno = sv_errno;
154 		return (-1);
155 	}
156 	trace2(TR__t_snd_conn_req, 1, fd);
157 	return (0);
158 }
159 
160 
161 
162 /*
163  * Rcv_conn_con - get connection confirmation off
164  * of read queue
165  * Note:
166  *      - called holding the tiptr->ti_lock
167  */
168 int
169 _t_rcv_conn_con(
170 	struct _ti_user *tiptr,
171 	struct t_call *call,
172 	struct strbuf *ctlbufp,
173 	int api_semantics)
174 {
175 	struct strbuf databuf;
176 	union T_primitives *pptr;
177 	int retval, fd, sv_errno;
178 	int didralloc;
179 
180 	int flg = 0;
181 
182 	trace2(TR__t_rcv_conn_con, 0, fd);
183 
184 	fd = tiptr->ti_fd;
185 
186 	if (tiptr->ti_servtype == T_CLTS) {
187 		t_errno = TNOTSUPPORT;
188 		trace2(TR__t_rcv_conn_con, 1, fd);
189 		return (-1);
190 	}
191 
192 	/*
193 	 * see if there is something in look buffer
194 	 */
195 	if (tiptr->ti_lookcnt > 0) {
196 		t_errno = TLOOK;
197 		trace2(TR__t_rcv_conn_con, 1, fd);
198 		return (-1);
199 	}
200 
201 	ctlbufp->len = 0;
202 	/*
203 	 * Acquire databuf for use in sending/receiving data part
204 	 */
205 	if (_t_acquire_databuf(tiptr, &databuf, &didralloc) < 0) {
206 		sv_errno = errno;
207 		trace2(TR__t_rcv_conn_con, 1, fd);
208 		errno = sv_errno;
209 		return (-1);
210 	}
211 
212 	/*
213 	 * This is a call that may block indefinitely so we drop the
214 	 * lock and allow signals in MT case here and reacquire it.
215 	 * Error case should roll back state changes done above
216 	 * (happens to be no state change here)
217 	 */
218 	sig_mutex_unlock(&tiptr->ti_lock);
219 	if ((retval = getmsg(fd, ctlbufp, &databuf, &flg)) < 0) {
220 		sv_errno = errno;
221 		if (errno == EAGAIN)
222 			t_errno = TNODATA;
223 		else
224 			t_errno = TSYSERR;
225 		sig_mutex_lock(&tiptr->ti_lock);
226 		errno = sv_errno;
227 		goto err_out;
228 	}
229 	sig_mutex_lock(&tiptr->ti_lock);
230 
231 	if (databuf.len == -1) databuf.len = 0;
232 
233 	/*
234 	 * did we get entire message
235 	 */
236 	if (retval > 0) {
237 		t_errno = TSYSERR;
238 		errno = EIO;
239 		goto err_out;
240 	}
241 
242 	/*
243 	 * is cntl part large enough to determine message type?
244 	 */
245 	if (ctlbufp->len < (int)sizeof (t_scalar_t)) {
246 		t_errno = TSYSERR;
247 		errno = EPROTO;
248 		goto err_out;
249 	}
250 
251 	pptr = (union T_primitives *)ctlbufp->buf;
252 
253 	switch (pptr->type) {
254 
255 	case T_CONN_CON:
256 
257 		if ((ctlbufp->len < (int)sizeof (struct T_conn_con)) ||
258 		    (pptr->conn_con.OPT_length != 0 &&
259 		    (ctlbufp->len < (int)(pptr->conn_con.OPT_length +
260 		    pptr->conn_con.OPT_offset)))) {
261 			t_errno = TSYSERR;
262 			errno = EPROTO;
263 			goto err_out;
264 		}
265 
266 		if (call != NULL) {
267 			/*
268 			 * Note: Buffer overflow is an error in XTI
269 			 * only if netbuf.maxlen > 0
270 			 */
271 			if (_T_IS_TLI(api_semantics) || call->addr.maxlen > 0) {
272 				if (TLEN_GT_NLEN(pptr->conn_con.RES_length,
273 				    call->addr.maxlen)) {
274 					t_errno = TBUFOVFLW;
275 					goto err_out;
276 				}
277 				(void) memcpy(call->addr.buf,
278 				    ctlbufp->buf + pptr->conn_con.RES_offset,
279 				    (size_t)pptr->conn_con.RES_length);
280 				call->addr.len = pptr->conn_con.RES_length;
281 			}
282 			if (_T_IS_TLI(api_semantics) || call->opt.maxlen > 0) {
283 				if (TLEN_GT_NLEN(pptr->conn_con.OPT_length,
284 				    call->opt.maxlen)) {
285 					t_errno = TBUFOVFLW;
286 					goto err_out;
287 				}
288 				(void) memcpy(call->opt.buf,
289 				    ctlbufp->buf + pptr->conn_con.OPT_offset,
290 				    (size_t)pptr->conn_con.OPT_length);
291 				call->opt.len = pptr->conn_con.OPT_length;
292 			}
293 			if (_T_IS_TLI(api_semantics) ||
294 			    call->udata.maxlen > 0) {
295 				if (databuf.len > (int)call->udata.maxlen) {
296 					t_errno = TBUFOVFLW;
297 					goto err_out;
298 				}
299 				(void) memcpy(call->udata.buf, databuf.buf,
300 				    (size_t)databuf.len);
301 				call->udata.len = databuf.len;
302 			}
303 			/*
304 			 * since a confirmation seq number
305 			 * is -1 by default
306 			 */
307 			call->sequence = (int)-1;
308 		}
309 		if (didralloc)
310 			free(databuf.buf);
311 		else
312 			tiptr->ti_rcvbuf = databuf.buf;
313 		trace2(TR__t_rcv_conn_con, 1, fd);
314 		return (0);
315 
316 	case T_DISCON_IND:
317 
318 		/*
319 		 * if disconnect indication then append it to
320 		 * the "look bufffer" list.
321 		 * This may result in MT case for the process
322 		 * signal mask to be temporarily masked to
323 		 * ensure safe memory allocation.
324 		 */
325 
326 		if (_t_register_lookevent(tiptr, databuf.buf, databuf.len,
327 					ctlbufp->buf, ctlbufp->len) < 0) {
328 			t_errno = TSYSERR;
329 			errno = ENOMEM;
330 			goto err_out;
331 		}
332 		t_errno = TLOOK;
333 		goto err_out;
334 
335 	default:
336 		break;
337 	}
338 
339 	t_errno = TSYSERR;
340 	trace2(TR__t_rcv_conn_con, 1, fd);
341 	errno = EPROTO;
342 err_out:
343 	sv_errno = errno;
344 	if (didralloc)
345 		free(databuf.buf);
346 	else
347 		tiptr->ti_rcvbuf = databuf.buf;
348 	trace2(TR__t_rcv_conn_con, 1, fd);
349 	errno = sv_errno;
350 	return (-1);
351 }
352