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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39 /*
40 * Kernel TLI-like function to allow a trasnport endpoint to initiate a
41 * connection to another transport endpoint. This function will wait for
42 * an ack and a T_CONN_CON before returning.
43 *
44 * Returns:
45 * 0 on success, and if rcvcall is non-NULL it shall be
46 * filled with the connection confirm data.
47 * Otherwise a positive error code.
48 */
49
50 #include <sys/param.h>
51 #include <sys/types.h>
52 #include <sys/user.h>
53 #include <sys/file.h>
54 #include <sys/vnode.h>
55 #include <sys/errno.h>
56 #include <sys/stream.h>
57 #include <sys/ioctl.h>
58 #include <sys/stropts.h>
59 #include <sys/tihdr.h>
60 #include <sys/timod.h>
61 #include <sys/tiuser.h>
62 #include <sys/t_kuser.h>
63 #include <sys/strsubr.h>
64 #include <sys/sysmacros.h>
65 #include <sys/strsun.h>
66
67
68 int
t_kconnect(TIUSER * tiptr,struct t_call * sndcall,struct t_call * rcvcall)69 t_kconnect(TIUSER *tiptr, struct t_call *sndcall, struct t_call *rcvcall)
70 {
71 int len;
72 int msgsz;
73 size_t hdrsz;
74 struct T_conn_req *creq;
75 union T_primitives *pptr;
76 mblk_t *nbp;
77 file_t *fp;
78 mblk_t *bp;
79 int error;
80 int flag;
81
82 error = 0;
83
84 fp = tiptr->fp;
85 msgsz = (int)TCONNREQSZ;
86 /*
87 * Usually connect()s are performed with the credential of the caller;
88 * in this particular case we specifically use the credential of
89 * the opener as this call is typically done in the context of a user
90 * process but on behalf of the kernel, e.g., a client connection
91 * to a server which is later shared by different users.
92 * At open time, we make sure to set fp->f_cred to kcred if such is
93 * the case.
94 *
95 * Note: if the receiver uses SCM_UCRED/getpeerucred the pid will
96 * appear as -1.
97 */
98 while (!(bp = allocb_cred(msgsz + sndcall->addr.len + sndcall->opt.len,
99 fp->f_cred, NOPID))) {
100 if (strwaitbuf(msgsz + sndcall->addr.len + sndcall->opt.len,
101 BPRI_LO))
102 return (ENOSR);
103 }
104
105 /* LINTED pointer alignment */
106 creq = (struct T_conn_req *)bp->b_wptr;
107 creq->PRIM_type = T_CONN_REQ;
108 creq->DEST_length = (t_scalar_t)sndcall->addr.len;
109 creq->OPT_length = (t_scalar_t)sndcall->opt.len;
110
111 if (sndcall->addr.len) {
112 bcopy(sndcall->addr.buf, (bp->b_wptr+msgsz), sndcall->addr.len);
113 creq->DEST_offset = (t_scalar_t)msgsz;
114 msgsz += sndcall->addr.len;
115 } else
116 creq->DEST_offset = (t_scalar_t)0;
117
118 if (sndcall->opt.len) {
119 bcopy(sndcall->opt.buf, (bp->b_wptr+msgsz), sndcall->opt.len);
120 creq->OPT_offset = (t_scalar_t)msgsz;
121 msgsz += sndcall->opt.len;
122 } else
123 creq->OPT_offset = (t_scalar_t)0;
124
125 bp->b_datap->db_type = M_PROTO;
126 bp->b_wptr += msgsz;
127
128 /*
129 * copy the users data, if any.
130 */
131 if (sndcall->udata.len) {
132 /*
133 * if CO then we would allocate a data block and
134 * put the users connect data into it.
135 */
136 KTLILOG(1,
137 "Attempt to send connectionless data on T_CONN_REQ\n", 0);
138 freemsg(bp);
139 return (EPROTO);
140 }
141
142 flag = fp->f_flag;
143
144 /*
145 * send it
146 */
147 if ((error = tli_send(tiptr, bp, flag)) != 0)
148 return (error);
149
150 /*
151 * wait for acknowledgment
152 */
153 if ((error = get_ok_ack(tiptr, T_CONN_REQ, flag)) != 0)
154 return (error);
155
156 bp = NULL;
157 /*
158 * wait for CONfirm
159 */
160 if ((error = tli_recv(tiptr, &bp, flag)) != 0)
161 return (error);
162
163 if (bp->b_datap->db_type != M_PROTO) {
164 freemsg(bp);
165 return (EPROTO);
166 }
167
168 /* LINTED pointer alignment */
169 pptr = (union T_primitives *)bp->b_rptr;
170 switch (pptr->type) {
171 case T_CONN_CON:
172 hdrsz = MBLKL(bp);
173
174 /*
175 * check everything for consistency
176 */
177 if (hdrsz < TCONNCONSZ ||
178 hdrsz < (pptr->conn_con.OPT_length +
179 pptr->conn_con.OPT_offset) ||
180 hdrsz < (pptr->conn_con.RES_length +
181 pptr->conn_con.RES_offset)) {
182 error = EPROTO;
183 freemsg(bp);
184 break;
185 }
186
187 if (rcvcall != NULL) {
188 /*
189 * okay, so now we copy them
190 */
191 len = MIN(pptr->conn_con.RES_length,
192 rcvcall->addr.maxlen);
193 bcopy(bp->b_rptr + pptr->conn_con.RES_offset,
194 rcvcall->addr.buf, len);
195 rcvcall->addr.len = len;
196
197 len = MIN(pptr->conn_con.OPT_length,
198 rcvcall->opt.maxlen);
199 bcopy(bp->b_rptr + pptr->conn_con.OPT_offset,
200 rcvcall->opt.buf, len);
201 rcvcall->opt.len = len;
202
203 if (bp->b_cont) {
204 nbp = bp;
205 bp = bp->b_cont;
206 msgsz = (int)MBLKL(bp);
207 len = MIN(msgsz, rcvcall->udata.maxlen);
208 bcopy(bp->b_rptr, rcvcall->udata.buf, len);
209 rcvcall->udata.len = len;
210 freemsg(nbp);
211 }
212 } else {
213 freemsg(bp);
214 }
215 break;
216
217 case T_DISCON_IND:
218 /*
219 * TCP puts the errno here, i.e.
220 * ETIMEDOUT, ECONNREFUSED
221 */
222 error = pptr->discon_ind.DISCON_reason;
223 freemsg(bp);
224 break;
225
226 default:
227 error = EPROTO;
228 freemsg(bp);
229 break;
230 }
231 return (error);
232 }
233