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