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