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 /*
32 * t_rcvudata.c and t_rcvvudata.c are very similar and contain common code.
33 * Any changes to either of them should be reviewed to see whether they
34 * are applicable to the other file.
35 */
36 #include "mt.h"
37 #include <string.h>
38 #include <stdlib.h>
39 #include <errno.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 <syslog.h>
47 #include "tx.h"
48
49
50 int
_tx_rcvudata(int fd,struct t_unitdata * unitdata,int * flags,int api_semantics)51 _tx_rcvudata(
52 int fd,
53 struct t_unitdata *unitdata,
54 int *flags,
55 int api_semantics
56 )
57 {
58 struct strbuf ctlbuf;
59 int retval;
60 union T_primitives *pptr;
61 struct _ti_user *tiptr;
62 int sv_errno;
63 int didalloc;
64 int flg = 0;
65
66 if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL)
67 return (-1);
68 sig_mutex_lock(&tiptr->ti_lock);
69
70 if (tiptr->ti_servtype != T_CLTS) {
71 t_errno = TNOTSUPPORT;
72 sig_mutex_unlock(&tiptr->ti_lock);
73 return (-1);
74 }
75
76 if (_T_IS_XTI(api_semantics)) {
77 /*
78 * User level state verification only done for XTI
79 * because doing for TLI may break existing applications
80 */
81 if (tiptr->ti_state != T_IDLE) {
82 t_errno = TOUTSTATE;
83 sig_mutex_unlock(&tiptr->ti_lock);
84 return (-1);
85 }
86 }
87
88
89 /*
90 * check if there is something in look buffer
91 */
92 if (tiptr->ti_lookcnt > 0) {
93 sig_mutex_unlock(&tiptr->ti_lock);
94 t_errno = TLOOK;
95 return (-1);
96 }
97
98 /*
99 * Acquire ctlbuf for use in sending/receiving control part
100 * of the message.
101 */
102 if (_t_acquire_ctlbuf(tiptr, &ctlbuf, &didalloc) < 0) {
103 sv_errno = errno;
104 sig_mutex_unlock(&tiptr->ti_lock);
105 errno = sv_errno;
106 return (-1);
107 }
108
109 *flags = 0;
110
111 /*
112 * This is a call that may block indefinitely so we drop the
113 * lock and allow signals in MT case here and reacquire it.
114 * Error case should roll back state changes done above
115 * (happens to be no state change here)
116 */
117 sig_mutex_unlock(&tiptr->ti_lock);
118 if ((retval = getmsg(fd, &ctlbuf, (struct strbuf *)&unitdata->udata,
119 &flg)) < 0) {
120 if (errno == EAGAIN)
121 t_errno = TNODATA;
122 else
123 t_errno = TSYSERR;
124 sv_errno = errno;
125 sig_mutex_lock(&tiptr->ti_lock);
126 errno = sv_errno;
127 goto err_out;
128 }
129 sig_mutex_lock(&tiptr->ti_lock);
130
131 if (((struct strbuf *)&unitdata->udata)->len == -1)
132 unitdata->udata.len = 0;
133
134 /*
135 * is there control piece with data?
136 */
137 if (ctlbuf.len > 0) {
138 if (ctlbuf.len < (int)sizeof (t_scalar_t)) {
139 unitdata->udata.len = 0;
140 t_errno = TSYSERR;
141 errno = EPROTO;
142 goto err_out;
143 }
144
145 /* LINTED pointer cast */
146 pptr = (union T_primitives *)ctlbuf.buf;
147
148 switch (pptr->type) {
149
150 case T_UNITDATA_IND:
151 if ((ctlbuf.len <
152 (int)sizeof (struct T_unitdata_ind)) ||
153 (pptr->unitdata_ind.OPT_length &&
154 (ctlbuf.len < (int)(pptr->unitdata_ind.OPT_length
155 + pptr->unitdata_ind.OPT_offset)))) {
156 t_errno = TSYSERR;
157 unitdata->udata.len = 0;
158 errno = EPROTO;
159 goto err_out;
160 }
161
162 if (_T_IS_TLI(api_semantics) ||
163 unitdata->addr.maxlen > 0) {
164 if (TLEN_GT_NLEN(pptr->unitdata_ind.SRC_length,
165 unitdata->addr.maxlen)) {
166 t_errno = TBUFOVFLW;
167 unitdata->udata.len = 0;
168 goto err_out;
169 }
170 (void) memcpy(unitdata->addr.buf,
171 ctlbuf.buf + pptr->unitdata_ind.SRC_offset,
172 (size_t)pptr->unitdata_ind.SRC_length);
173 unitdata->addr.len =
174 pptr->unitdata_ind.SRC_length;
175 }
176 if (_T_IS_TLI(api_semantics) ||
177 unitdata->opt.maxlen > 0) {
178 if (TLEN_GT_NLEN(pptr->unitdata_ind.OPT_length,
179 unitdata->opt.maxlen)) {
180 t_errno = TBUFOVFLW;
181 unitdata->udata.len = 0;
182 goto err_out;
183 }
184 (void) memcpy(unitdata->opt.buf, ctlbuf.buf +
185 pptr->unitdata_ind.OPT_offset,
186 (size_t)pptr->unitdata_ind.OPT_length);
187 unitdata->opt.len =
188 pptr->unitdata_ind.OPT_length;
189 }
190 if (retval & MOREDATA)
191 *flags |= T_MORE;
192 /*
193 * No state changes happens on T_RCVUDATA
194 * event (NOOP). We do it only to log errors.
195 */
196 _T_TX_NEXTSTATE(T_RCVUDATA, tiptr,
197 "t_rcvudata: invalid state event T_RCVUDATA");
198
199 if (didalloc)
200 free(ctlbuf.buf);
201 else
202 tiptr->ti_ctlbuf = ctlbuf.buf;
203
204 sig_mutex_unlock(&tiptr->ti_lock);
205 return (0);
206
207 case T_UDERROR_IND:
208 if (_t_register_lookevent(tiptr, 0, 0, ctlbuf.buf,
209 ctlbuf.len) < 0) {
210 t_errno = TSYSERR;
211 errno = ENOMEM;
212 goto err_out;
213 }
214 unitdata->udata.len = 0;
215 t_errno = TLOOK;
216 goto err_out;
217
218 default:
219 break;
220 }
221
222 t_errno = TSYSERR;
223 errno = EPROTO;
224 goto err_out;
225
226 } else { /* else part of "if (ctlbuf.len > 0)" */
227 unitdata->addr.len = 0;
228 unitdata->opt.len = 0;
229 /*
230 * only data in message no control piece
231 */
232 if (retval & MOREDATA)
233 *flags = T_MORE;
234 /*
235 * No state transition occurs on
236 * event T_RCVUDATA. We do it only to
237 * log errors.
238 */
239 _T_TX_NEXTSTATE(T_RCVUDATA, tiptr,
240 "t_rcvudata: invalid state event T_RCVUDATA");
241 if (didalloc)
242 free(ctlbuf.buf);
243 else
244 tiptr->ti_ctlbuf = ctlbuf.buf;
245 sig_mutex_unlock(&tiptr->ti_lock);
246 return (0);
247 }
248 /* NOTREACHED */
249 err_out:
250 sv_errno = errno;
251 if (didalloc)
252 free(ctlbuf.buf);
253 else
254 tiptr->ti_ctlbuf = ctlbuf.buf;
255 sig_mutex_unlock(&tiptr->ti_lock);
256 errno = sv_errno;
257 return (-1);
258 }
259