xref: /illumos-gate/usr/src/uts/common/ktli/t_kconnect.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 1998 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 /*
43  * Kernel TLI-like function to allow a trasnport endpoint to initiate a
44  * connection to another transport endpoint.  This function will wait for
45  * an ack and a T_CONN_CON before returning.
46  *
47  * Returns:
48  * 	0 on success, and if rcvcall is non-NULL it shall be
49  * 	filled with the connection confirm data.
50  * 	Otherwise a positive error code.
51  */
52 
53 #include <sys/param.h>
54 #include <sys/types.h>
55 #include <sys/user.h>
56 #include <sys/file.h>
57 #include <sys/vnode.h>
58 #include <sys/errno.h>
59 #include <sys/stream.h>
60 #include <sys/ioctl.h>
61 #include <sys/stropts.h>
62 #include <sys/tihdr.h>
63 #include <sys/timod.h>
64 #include <sys/tiuser.h>
65 #include <sys/t_kuser.h>
66 #include <sys/strsubr.h>
67 #include <sys/sysmacros.h>
68 
69 
70 int
71 t_kconnect(TIUSER *tiptr, struct t_call *sndcall, struct t_call *rcvcall)
72 {
73 	int			len;
74 	int			msgsz;
75 	size_t			hdrsz;
76 	struct T_conn_req	*creq;
77 	union T_primitives	*pptr;
78 	mblk_t			*nbp;
79 	file_t			*fp;
80 	mblk_t			*bp;
81 	int			error;
82 	int			flag;
83 
84 	error = 0;
85 
86 	fp = tiptr->fp;
87 	msgsz = (int)TCONNREQSZ;
88 	while (!(bp = allocb(msgsz + sndcall->addr.len + sndcall->opt.len,
89 	    BPRI_LO))) {
90 		if (strwaitbuf(msgsz + sndcall->addr.len + sndcall->opt.len,
91 		    BPRI_LO))
92 			return (ENOSR);
93 	}
94 
95 	/* LINTED pointer alignment */
96 	creq = (struct T_conn_req *)bp->b_wptr;
97 	creq->PRIM_type = T_CONN_REQ;
98 	creq->DEST_length = (t_scalar_t)sndcall->addr.len;
99 	creq->OPT_length = (t_scalar_t)sndcall->opt.len;
100 
101 	if (sndcall->addr.len) {
102 		bcopy(sndcall->addr.buf, (bp->b_wptr+msgsz), sndcall->addr.len);
103 		creq->DEST_offset = (t_scalar_t)msgsz;
104 		msgsz += sndcall->addr.len;
105 	} else
106 		creq->DEST_offset = (t_scalar_t)0;
107 
108 	if (sndcall->opt.len) {
109 		bcopy(sndcall->opt.buf, (bp->b_wptr+msgsz), sndcall->opt.len);
110 		creq->OPT_offset = (t_scalar_t)msgsz;
111 		msgsz += sndcall->opt.len;
112 	} else
113 		creq->OPT_offset = (t_scalar_t)0;
114 
115 	bp->b_datap->db_type = M_PROTO;
116 	bp->b_wptr += msgsz;
117 
118 	/*
119 	 * copy the users data, if any.
120 	 */
121 	if (sndcall->udata.len) {
122 		/*
123 		 * if CO then we would allocate a data block and
124 		 * put the users connect data into it.
125 		 */
126 		KTLILOG(1,
127 		    "Attempt to send connectionless data on T_CONN_REQ\n", 0);
128 		freemsg(bp);
129 		return (EPROTO);
130 	}
131 
132 	flag = fp->f_flag;
133 
134 	/*
135 	 * send it
136 	 */
137 	if ((error = tli_send(tiptr, bp, flag)) != 0)
138 		return (error);
139 
140 	/*
141 	 * wait for acknowledgment
142 	 */
143 	if ((error = get_ok_ack(tiptr, T_CONN_REQ, flag)) != 0)
144 		return (error);
145 
146 	bp = NULL;
147 	/*
148 	 * wait for CONfirm
149 	 */
150 	if ((error = tli_recv(tiptr, &bp, flag)) != 0)
151 		return (error);
152 
153 	if (bp->b_datap->db_type != M_PROTO) {
154 		freemsg(bp);
155 		return (EPROTO);
156 	}
157 
158 	/* LINTED pointer alignment */
159 	pptr = (union T_primitives *)bp->b_rptr;
160 	switch (pptr->type) {
161 	case T_CONN_CON:
162 		hdrsz = bp->b_wptr -  bp->b_rptr;
163 
164 		/*
165 		 * check everything for consistency
166 		 */
167 		if (hdrsz < TCONNCONSZ ||
168 		    hdrsz < (pptr->conn_con.OPT_length +
169 		    pptr->conn_con.OPT_offset) ||
170 		    hdrsz < (pptr->conn_con.RES_length +
171 		    pptr->conn_con.RES_offset)) {
172 			error = EPROTO;
173 			freemsg(bp);
174 			break;
175 		}
176 
177 		if (rcvcall != NULL) {
178 			/*
179 			 * okay, so now we copy them
180 			 */
181 			len = MIN(pptr->conn_con.RES_length,
182 			    rcvcall->addr.maxlen);
183 			bcopy(bp->b_rptr + pptr->conn_con.RES_offset,
184 			    rcvcall->addr.buf, len);
185 			rcvcall->addr.len = len;
186 
187 			len = MIN(pptr->conn_con.OPT_length,
188 			    rcvcall->opt.maxlen);
189 			bcopy(bp->b_rptr + pptr->conn_con.OPT_offset,
190 			    rcvcall->opt.buf, len);
191 			rcvcall->opt.len = len;
192 
193 			if (bp->b_cont) {
194 				nbp = bp;
195 				bp = bp->b_cont;
196 				msgsz = (int)(bp->b_wptr - bp->b_rptr);
197 				len = MIN(msgsz, rcvcall->udata.maxlen);
198 				bcopy(bp->b_rptr, rcvcall->udata.buf, len);
199 				rcvcall->udata.len = len;
200 				freemsg(nbp);
201 			}
202 		} else {
203 			freemsg(bp);
204 		}
205 		break;
206 
207 	default:
208 		error = EPROTO;
209 		freemsg(bp);
210 		break;
211 	}
212 	return (error);
213 }
214