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/dccp_impl.h>
42 #include <inet/ip.h>
43 #include <inet/proto_set.h>
44
45 #include <sys/cmn_err.h>
46
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 * This routine responds to T_INFO_REQ messages.
122 */
123 void
124 dccp_info_req(dccp_t *dccp, mblk_t *mp)
125 {
126 mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO,
127 T_INFO_ACK);
128 if (mp == NULL) {
129 dccp_err_ack(dccp, mp, TSYSERR, ENOMEM);
130 return;
131 }
132
133 dccp_copy_info((struct T_info_ack *)mp->b_rptr, dccp);
134 putnext(dccp->dccp_connp->conn_rq, mp);
135 }
136
137 /*
138 * This routine responds to T_ADDR_REQ messages.
139 */
140 void
141 dccp_addr_req(dccp_t *dccp, mblk_t *mp)
142 {
143 conn_t *connp = dccp->dccp_connp;
144 mblk_t *ackmp;
145 uint_t addrlen;
146 struct sockaddr *sa;
147 struct T_addr_ack *taa;
148
149 /* XXX */
150 }
151
152 /*
153 * Helper function to generate TPI errors acks.
154 */
155 void
156 dccp_err_ack(dccp_t *dccp, mblk_t *mp, int t_error, int sys_error)
157 {
158 if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) {
159 putnext(dccp->dccp_connp->conn_rq, mp);
160 }
161 }
162
163 void
164 dccp_tpi_connect(dccp_t *dccp, mblk_t *mp)
165 {
166 conn_t *connp = dccp->dccp_connp;
167 queue_t *q = connp->conn_wq;
168 struct sockaddr *sa;
169 struct T_conn_req *tcr;
170 sin_t *sin;
171 sin6_t *sin6;
172 cred_t *cr;
173 pid_t cpid;
174 socklen_t len;
175 int error;
176
177 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_connect");
178
179 cr = msg_getcred(mp, &cpid);
180 ASSERT(cr != NULL);
181 if (cr == NULL) {
182 dccp_err_ack(dccp, mp, TSYSERR, EINVAL);
183 return;
184 }
185
186 tcr = (struct T_conn_req *)mp->b_rptr;
187
188 ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX);
189 if ((mp->b_wptr - mp->b_rptr) < sizeof (*tcr)) {
190 dccp_err_ack(dccp, mp, TPROTO, 0);
191 return;
192 }
193
194 error = proto_verify_ip_addr(connp->conn_family, sa, len);
195 if (error != 0) {
196 dccp_err_ack(dccp, mp, TSYSERR, 0);
197 return;
198 }
199
200 error = dccp_do_connect(dccp->dccp_connp, sa, len, cr, cpid);
201 if (error < 0) {
202 mp = mi_tpi_err_ack_alloc(mp, -error, 0);
203 } else if (error > 0) {
204 mp = mi_tpi_err_ack_alloc(mp, TSYSERR, error);
205 } else {
206 mp = mi_tpi_ok_ack_alloc(mp);
207 }
208 }
209
210 int
211 dccp_tpi_close(queue_t *q, int flags)
212 {
213 conn_t *connp;
214
215 ASSERT(WR(q)->q_next == NULL);
216
217 connp = Q_TO_CONN(q);
218
219 dccp_close_common(connp, flags);
220
221 qprocsoff(q);
222 inet_minor_free(connp->conn_minor_arena, connp->conn_dev);
223
224 return (0);
225 }
226
227 int
228 dccp_tpi_close_accept(queue_t *q)
229 {
230 vmem_t *minor_arena;
231 dev_t conn_dev;
232
233 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_close_accept");
234
235 return (0);
236 }
237
238 boolean_t
239 dccp_conn_con(dccp_t *dccp, uchar_t *iphdr, mblk_t *idmp,
240 mblk_t **defermp, ip_recv_attr_t *ira)
241 {
242 conn_t *connp = dccp->dccp_connp;
243 sin_t sin;
244 sin6_t sin6;
245 mblk_t *mp;
246 char *optp = NULL;
247 int optlen = 0;
248
249 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_conn_con");
250
251 if (defermp != NULL) {
252 *defermp = NULL;
253 }
254
255 if (IPH_HDR_VERSION(iphdr) == IPV4_VERSION) {
256 /* Packet is IPv4 */
257 if (connp->conn_family == AF_INET) {
258 sin = sin_null;
259 sin.sin_addr.s_addr = connp->conn_faddr_v4;
260 sin.sin_port = connp->conn_fport;
261 sin.sin_family = AF_INET;
262 mp = mi_tpi_conn_con(NULL, (char *)&sin,
263 (int)sizeof (sin_t), optp, optlen);
264 } else {
265 sin6 = sin6_null;
266 sin6.sin6_addr = connp->conn_faddr_v6;
267 sin6.sin6_port = connp->conn_fport;
268 sin6.sin6_family = AF_INET6;
269 mp = mi_tpi_conn_con(NULL, (char *)&sin6,
270 (int)sizeof (sin6_t), optp, optlen);
271 }
272 } else {
273 ip6_t *ip6h = (ip6_t *)iphdr;
274
275 ASSERT(IPH_HDR_VERSION(iphdr) == IPV6_VERSION);
276 ASSERT(connp->conn_family == AF_INET6);
277
278 sin6 = sin6_null;
279 sin6.sin6_addr = connp->conn_faddr_v6;
280 sin6.sin6_port = connp->conn_fport;
281 sin6.sin6_family = AF_INET6;
282 sin6.sin6_flowinfo = ip6h->ip6_vcf & ~IPV6_VERS_AND_FLOW_MASK;
283 mp = mi_tpi_conn_con(NULL, (char *)&sin6,
284 (int)sizeof (sin6_t), optp, optlen);
285 }
286
287 if (!mp) {
288 return (B_FALSE);
289 }
290
291 mblk_copycred(mp, idmp);
292
293 if (defermp == NULL) {
294 if (IPCL_IS_NONSTR(connp)) {
295 cmn_err(CE_NOTE, "calling su_connected");
296 (*connp->conn_upcalls->su_connected)
297 (connp->conn_upper_handle, dccp->dccp_connid,
298 ira->ira_cred, ira->ira_cpid);
299 freemsg(mp);
300 } else {
301 if (ira->ira_cred != NULL) {
302 /* So that getpeerucred works for TPI sockfs */
303 mblk_setcred(mp, ira->ira_cred, ira->ira_cpid);
304 }
305 putnext(connp->conn_rq, mp);
306 }
307 } else {
308 *defermp = mp;
309 }
310
311 /* XXX */
312 return (B_TRUE);
313 }
314
315 /*
316 * Routine to get the values of options.
317 */
318 int
319 dccp_tpi_opt_get(queue_t *q, int level, int name, uchar_t *ptr)
320 {
321 return (dccp_opt_get(Q_TO_CONN(q), level, name, ptr));
322 }
323
324 /*
325 * Routine to set the values of options.
326 */
327 /* ARGSUSED */
328 int
329 dccp_tpi_opt_set(queue_t *q, uint_t optset_context, int level, int name,
330 uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp,
331 void *thisdg_attrs, cred_t *cr)
332 {
333 conn_t *connp = Q_TO_CONN(q);
334
335 return (dccp_opt_set(connp, optset_context, level, name, inlen, invalp,
336 outlenp, outvalp, thisdg_attrs, cr));
337 }
338
339 void
340 dccp_tpi_accept(queue_t *q, mblk_t *mp)
341 {
342 struct T_ok_ack *ok;
343 struct T_conn_res *conn_res;
344 conn_t *econnp;
345 dccp_t *eager;
346 dccp_t *listener;
347 queue_t *rq = RD(q);
348 mblk_t *discon_mp;
349 cred_t *cr;
350
351 cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_accept");
352
353 ASSERT(DB_TYPE(mp) == M_PROTO);
354
355 cr = msg_getcred(mp, NULL);
356 ASSERT(cr != NULL);
357 if (cr == NULL) {
358 mp = mi_tpi_err_ack_alloc(mp, TSYSERR, EINVAL);
359 if (mp != NULL) {
360 putnext(rq, mp);
361 }
362 return;
363 }
364
365 conn_res = (struct T_conn_res *)mp->b_rptr;
366 ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX);
367 if ((mp->b_wptr - mp->b_rptr) < sizeof (struct T_conn_res)) {
368 mp = mi_tpi_err_ack_alloc(mp, TPROTO, 0);
369 if (mp != NULL) {
370 putnext(rq, mp);
371 }
372 return;
373 }
374
375 switch (conn_res->PRIM_type) {
376 case O_T_CONN_RES:
377 case T_CONN_RES:
378 putnext(rq, mp);
379 return;
380 default:
381 mp = mi_tpi_err_ack_alloc(mp, TNOTSUPPORT, 0);
382 if (mp != NULL) {
383 putnext(rq, mp);
384 }
385 return;
386 }
387 }
388
389 static void
390 dccp_accept_swap(dccp_t *listener, dccp_t *acceptor, dccp_t *eager)
391 {
392 conn_t *econnp;
393 conn_t *aconnp;
394 }
395
396 /*
397 * This runs at the tail end of accept processing on the squeue of the
398 * new connection.
399 */
400 static void
401 dccp_accept_finish(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
402 {
403 conn_t *connp = (conn_t *)arg;
404 dccp_t *dccp = connp->conn_dccp;
405 dccp_stack_t *dccps = dccp->dccp_dccps;
406 queue_t *q = connp->conn_rq;
407 struct stroptions *stropt;
408 struct sock_proto_props sopp;
409
410 /* Should never be called for non-STREAMS sockets */
411 ASSERT(!IPCL_IS_NONSTR(connp));
412
413 /* We should just receive a single mblk that fits a T_discon_ind */
414 ASSERT(mp->b_cont == NULL);
415
416 /* XXX */
417
418 dccp_get_proto_props(dccp, &sopp);
419
420 ASSERT(DB_REF(mp) == 1);
421 ASSERT(MBLKSIZE(mp) >= sizeof (struct stroptions));
422
423 DB_TYPE(mp) = M_SETOPTS;
424
425 /* XXX */
426
427 dccp->dccp_hard_binding = B_FALSE;
428
429 if (connp->conn_keepalive) {
430 dccp->dccp_ka_last_intrvl = 0;
431 dccp->dccp_ka_tid = DCCP_TIMER(dccp, dccp_keepalive_timer,
432 dccp->dccp_ka_interval);
433 }
434 }