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