7054 dmu_tx_hold_t should use refcount_t to track space
[unleashed.git] / usr / src / uts / common / ktli / t_kconnect.c
blobaf7fdaa588881fa512ff11a1fb3b2ccfd05d215e
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
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.
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.
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>
68 int
69 t_kconnect(TIUSER *tiptr, struct t_call *sndcall, struct t_call *rcvcall)
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;
82 error = 0;
84 fp = tiptr->fp;
85 msgsz = (int)TCONNREQSZ;
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.
95 * Note: if the receiver uses SCM_UCRED/getpeerucred the pid will
96 * appear as -1.
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);
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;
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;
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;
125 bp->b_datap->db_type = M_PROTO;
126 bp->b_wptr += msgsz;
129 * copy the users data, if any.
131 if (sndcall->udata.len) {
133 * if CO then we would allocate a data block and
134 * put the users connect data into it.
136 KTLILOG(1,
137 "Attempt to send connectionless data on T_CONN_REQ\n", 0);
138 freemsg(bp);
139 return (EPROTO);
142 flag = fp->f_flag;
145 * send it
147 if ((error = tli_send(tiptr, bp, flag)) != 0)
148 return (error);
151 * wait for acknowledgment
153 if ((error = get_ok_ack(tiptr, T_CONN_REQ, flag)) != 0)
154 return (error);
156 bp = NULL;
158 * wait for CONfirm
160 if ((error = tli_recv(tiptr, &bp, flag)) != 0)
161 return (error);
163 if (bp->b_datap->db_type != M_PROTO) {
164 freemsg(bp);
165 return (EPROTO);
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);
175 * check everything for consistency
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;
187 if (rcvcall != NULL) {
189 * okay, so now we copy them
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;
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;
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);
212 } else {
213 freemsg(bp);
215 break;
217 case T_DISCON_IND:
219 * TCP puts the errno here, i.e.
220 * ETIMEDOUT, ECONNREFUSED
222 error = pptr->discon_ind.DISCON_reason;
223 freemsg(bp);
224 break;
226 default:
227 error = EPROTO;
228 freemsg(bp);
229 break;
231 return (error);