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 /*
23 * Functions related to TPI.
24 */
25
26 #include <sys/types.h>
27 #include <sys/stream.h>
28 #include <sys/strsun.h>
29 #include <sys/strsubr.h>
30 #include <sys/stropts.h>
31 #include <sys/strlog.h>
32 #define _SUN_TPI_VERSION 2
33 #include <sys/tihdr.h>
34 #include <sys/suntpi.h>
35 #include <sys/xti_inet.h>
36 #include <sys/squeue_impl.h>
37 #include <sys/squeue.h>
38 #include <sys/tsol/tnet.h>
39
40 #include <inet/common.h>
41 #include <inet/ip.h>
42 #include <inet/proto_set.h>
43
44 #include <sys/cmn_err.h>
45
46 #include "dccp_impl.h"
47
48 /*
49 * This file contains functions related to the TPI interface.
50 */
51
52 /*
53 * XXX
54 */
55 static void
56 dccp_copy_info(struct T_info_ack *tia, dccp_t *dccp)
57 {
58 conn_t *connp = dccp->dccp_connp;
59 dccp_stack_t *dccps = dccp->dccp_dccps;
60 extern struct T_info_ack dccp_g_t_info_ack;
61 extern struct T_info_ack dccp_g_t_info_ack_v6;
62
63 if (connp->conn_family == AF_INET6) {
64 *tia = dccp_g_t_info_ack_v6;
65 } else {
66 *tia = dccp_g_t_info_ack;
67 }
68
69 /* XXX */
70 }
71
72 /*
73 * XXX
74 */
75 void
76 dccp_do_capability_ack(dccp_t *dccp, struct T_capability_ack *tcap,
77 t_uscalar_t cap_bits1)
78 {
79 tcap->CAP_bits1 = 0;
80
81 if (cap_bits1 & TC1_INFO) {
82 dccp_copy_info(&tcap->INFO_ack, dccp);
83 tcap->CAP_bits1 |= TC1_INFO;
84 }
85
86 if (cap_bits1 & TC1_ACCEPTOR_ID) {
87 tcap->ACCEPTOR_id = dccp->dccp_acceptor_id;
88 tcap->CAP_bits1 |= TC1_ACCEPTOR_ID;
89 }
90 }
91
92 /*
93 * This routine responds to T_CAPABILITY_REQ messages.
94 */
95 void
96 dccp_capability_req(dccp_t *dccp, mblk_t *mp)
97 {
98 struct T_capability_ack *tcap;
99 t_uscalar_t cap_bits1;
100
101 if (MBLKL(mp) < sizeof (struct T_capability_req)) {
102 freemsg(mp);
103 return;
104 }
105
106 cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1;
107
108 mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack),
109 mp->b_datap->db_type, T_CAPABILITY_ACK);
110 if (mp == NULL) {
111 return;
112 }
113
114 tcap = (struct T_capability_ack *)mp->b_rptr;
115 dccp_do_capability_ack(dccp, tcap, cap_bits1);
116
117 putnext(dccp->dccp_connp->conn_rq, mp);
118 }
119
120 /*
121 * Helper function to generate TPI errors acks.
122 */
123 void
124 dccp_err_ack(dccp_t *dccp, mblk_t *mp, int t_error, int sys_error)
125 {
126 if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) {
127 putnext(dccp->dccp_connp->conn_rq, mp);
128 }
129 }
130
131 void
132 dccp_tpi_connect(dccp_t *dccp, mblk_t *mp)
133 {
134 conn_t *connp = dccp->dccp_connp;
135 queue_t *q = connp->conn_wq;
136 struct sockaddr *sa;
137 struct T_conn_req *tcr;
138 sin_t *sin;
139 sin6_t *sin6;
140 cred_t *cr;
141 pid_t cpid;
142 socklen_t len;
143 int error;
144
145 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_connect");
146
147 cr = msg_getcred(mp, &cpid);
148 ASSERT(cr != NULL);
149 if (cr == NULL) {
150 dccp_err_ack(dccp, mp, TSYSERR, EINVAL);
151 return;
152 }
153
154 tcr = (struct T_conn_req *)mp->b_rptr;
155
156 ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX);
157 if ((mp->b_wptr - mp->b_rptr) < sizeof (*tcr)) {
158 dccp_err_ack(dccp, mp, TPROTO, 0);
159 return;
160 }
161
162 error = proto_verify_ip_addr(connp->conn_family, sa, len);
163 if (error != 0) {
164 dccp_err_ack(dccp, mp, TSYSERR, 0);
165 return;
166 }
167
168 error = dccp_do_connect(dccp->dccp_connp, sa, len, cr, cpid);
169 if (error < 0) {
170 mp = mi_tpi_err_ack_alloc(mp, -error, 0);
171 } else if (error > 0) {
172 mp = mi_tpi_err_ack_alloc(mp, TSYSERR, error);
173 } else {
174 mp = mi_tpi_ok_ack_alloc(mp);
175 }
176 }
177
178 int
179 dccp_tpi_close(queue_t *q, int flags)
180 {
181 conn_t *connp;
182
183 ASSERT(WR(q)->q_next == NULL);
184
185 connp = Q_TO_CONN(q);
186
187 dccp_close_common(connp, flags);
188
189 qprocsoff(q);
190 inet_minor_free(connp->conn_minor_arena, connp->conn_dev);
191
192 return (0);
193 }
194
195 int
196 dccp_tpi_close_accept(queue_t *q)
197 {
198 vmem_t *minor_arena;
199 dev_t conn_dev;
200
201 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_close_accept");
202
203 return (0);
204 }
205
206 /*
207 * Options related functions.
208 */
209 int
210 dccp_tpi_opt_get(queue_t *q, int level, int name, uchar_t *ptr)
211 {
212 return (dccp_opt_get(Q_TO_CONN(q), level, name, ptr));
213 }
214
215 /* ARGSUSED */
216 int
217 dccp_tpi_opt_set(queue_t *q, uint_t optset_context, int level, int name,
218 uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp,
219 void *thisdg_attrs, cred_t *cr)
220 {
221 conn_t *connp = Q_TO_CONN(q);
222
223 return (dccp_opt_set(connp, optset_context, level, name, inlen, invalp,
224 outlenp, outvalp, thisdg_attrs, cr));
225 }
226
227 void
228 dccp_tpi_accept(queue_t *q, mblk_t *mp)
229 {
230 queue_t *rq = RD(q);
231
232 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_accept");
233 }