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
_t_snd_conn_req(struct _ti_user * tiptr,const struct t_call * call,struct strbuf * ctlbufp)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
_t_rcv_conn_con(struct _ti_user * tiptr,struct t_call * call,struct strbuf * ctlbufp,int api_semantics)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