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 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Copyright 2012 David Hoeppner. All rights reserved.
25 */
26
27 /*
28 * This file implements the Data Congestion Control Protocol (DCCP).
29 */
30
31 #include <sys/types.h>
32 #include <sys/stream.h>
33 #include <sys/stropts.h>
34 #include <sys/strlog.h>
35 #include <sys/strsun.h>
36 #define _SUN_TPI_VERSION 2
37 #include <sys/tihdr.h>
38 #include <sys/socket.h>
39 #include <sys/socketvar.h>
40 #include <sys/sockio.h>
41 #include <sys/vtrace.h>
42 #include <sys/sdt.h>
43 #include <sys/debug.h>
44 #include <sys/ddi.h>
45 #include <sys/isa_defs.h>
46 #include <sys/policy.h>
47 #include <sys/tsol/label.h>
48 #include <sys/tsol/tnet.h>
49 #include <inet/kstatcom.h>
50 #include <inet/snmpcom.h>
51
52 #include <sys/cmn_err.h>
53
54 #include "dccp_impl.h"
55 #include "dccp_stack.h"
56
57 int dccp_squeue_flag;
58
59 /* Setable in /etc/system */
60 uint_t dccp_bind_fanout_size = DCCP_BIND_FANOUT_SIZE;
61
62 static void dccp_notify(void *, ip_xmit_attr_t *, ixa_notify_type_t,
63 ixa_notify_arg_t);
64
65 /* Functions to register netstack */
66 static void *dccp_stack_init(netstackid_t, netstack_t *);
67 static void dccp_stack_fini(netstackid_t, void *);
68
69 /* Stream device open functions */
70 static int dccp_openv4(queue_t *, dev_t *, int, int, cred_t *);
71 static int dccp_openv6(queue_t *, dev_t *, int, int, cred_t *);
72 static int dccp_open(queue_t *, dev_t *, int, int, cred_t *,
73 boolean_t);
74
75 /* Write service routine */
76 static void dccp_wsrv(queue_t *);
77
78 /* Connection related functions */
79 static int dccp_connect_ipv4(dccp_t *, ipaddr_t *, in_port_t, uint_t);
80 static int dccp_connect_ipv6(dccp_t *, in6_addr_t *, in_port_t, uint32_t,
81 uint_t, uint32_t);
82
83 /* Initialise ISS */
84 static void dccp_iss_init(dccp_t *);
85
86 struct module_info dccp_rinfo = {
87 DCCP_MOD_ID, DCCP_MOD_NAME, 0, INFPSZ, DCCP_RECV_HIWATER,
88 DCCP_RECV_LOWATER
89 };
90
91 static struct module_info dccp_winfo = {
92 DCCP_MOD_ID, DCCP_MOD_NAME, 0, INFPSZ, 127, 16
93 };
94
95 /*
96 * Queue information structure with DCCP entry points.
97 */
98 struct qinit dccp_rinitv4 = {
99 NULL, (pfi_t)dccp_rsrv, dccp_openv4, dccp_tpi_close, NULL, &dccp_rinfo
100 };
101
102 struct qinit dccp_rinitv6 = {
103 NULL, (pfi_t)dccp_rsrv, dccp_openv6, dccp_tpi_close, NULL, &dccp_rinfo
104 };
105
106 struct qinit dccp_winit = {
107 (pfi_t)dccp_wput, (pfi_t)dccp_wsrv, NULL, NULL, NULL, &dccp_winfo
108 };
109
110 /* Initial entry point for TCP in socket mode */
111 struct qinit dccp_sock_winit = {
112 (pfi_t)dccp_wput_sock, (pfi_t)dccp_wsrv, NULL, NULL, NULL, &dccp_winfo
113 };
114
115 struct qinit dccp_fallback_sock_winit = {
116 (pfi_t)dccp_wput_fallback, NULL, NULL, NULL, NULL, &dccp_winfo
117 };
118 /*
119 * DCCP as acceptor STREAM.
120 */
121 struct qinit dccp_acceptor_rinit = {
122 NULL, (pfi_t)dccp_rsrv, NULL, dccp_tpi_close_accept, NULL, &dccp_winfo
123 };
124
125 struct qinit dccp_acceptor_winit = {
126 (pfi_t)dccp_tpi_accept, NULL, NULL, NULL, NULL, &dccp_winfo
127 };
128
129 /* AF_INET /dev/dccp */
130 struct streamtab dccpinfov4 = {
131 &dccp_rinitv4, &dccp_winit
132 };
133
134 /* AF_INET6 /dev/dccp6 */
135 struct streamtab dccpinfov6 = {
136 &dccp_rinitv6, &dccp_winit
137 };
138
139 /* Template for response to info request */
140 struct T_info_ack dccp_g_t_info_ack = {
141 T_INFO_ACK, /* PRIM_type */
142 0, /* TSDU_size */
143 T_INFINITE, /* ETSDU_size */
144 T_INVALID, /* CDATA_size */
145 T_INVALID, /* DDATA_size */
146 sizeof (sin_t), /* ADDR_size */
147 0, /* OPT_size - not initialized here */
148 TIDUSZ, /* TIDU_size */
149 T_COTS_ORD, /* SERV_type */
150 DCCPS_IDLE, /* CURRENT_state */
151 (XPG4_1|EXPINLINE) /* PROVIDER_flag */
152 };
153
154 struct T_info_ack dccp_g_t_info_ack_v6 = {
155 T_INFO_ACK, /* PRIM_type */
156 0, /* TSDU_size */
157 T_INFINITE, /* ETSDU_size */
158 T_INVALID, /* CDATA_size */
159 T_INVALID, /* DDATA_size */
160 sizeof (sin6_t), /* ADDR_size */
161 0, /* OPT_size - not initialized here */
162 TIDUSZ, /* TIDU_size */
163 T_COTS_ORD, /* SERV_type */
164 DCCPS_IDLE, /* CURRENT_state */
165 (XPG4_1|EXPINLINE) /* PROVIDER_flag */
166 };
167
168 /*
169 * DCCP Tunables.
170 */
171 extern mod_prop_info_t dccp_propinfo_tbl[];
172 extern int dccp_propinfo_count;
173
174 /*
175 * Register DCCP in ip netstack.
176 */
177 void
178 dccp_ddi_g_init(void)
179 {
180 netstack_register(NS_DCCP, dccp_stack_init, NULL, dccp_stack_fini);
181 }
182
183 /*
184 * Unregister DCCP from ip netstack.
185 */
186 void
187 dccp_ddi_g_destroy(void)
188 {
189 netstack_unregister(NS_DCCP);
190 }
191
192 #define INET_NAME "ip"
193
194 /*
195 * Initialize this DCCP stack instance.
196 */
197 static void *
198 dccp_stack_init(netstackid_t stackid, netstack_t *ns)
199 {
200 dccp_stack_t *dccps;
201 major_t major;
202 size_t arrsz;
203 int error;
204 int i;
205
206 dccps = kmem_zalloc(sizeof (*dccps), KM_SLEEP);
207 if (dccps == NULL) {
208 return (NULL);
209 }
210 dccps->dccps_netstack = ns;
211
212 /* Ports */
213 mutex_init(&dccps->dccps_epriv_port_lock, NULL, MUTEX_DEFAULT, NULL);
214 dccps->dccps_num_epriv_ports = DCCP_NUM_EPRIV_PORTS;
215 dccps->dccps_epriv_ports[0] = ULP_DEF_EPRIV_PORT1;
216 dccps->dccps_epriv_ports[1] = ULP_DEF_EPRIV_PORT2;
217 dccps->dccps_min_anonpriv_port = 512;
218
219 dccps->dccps_bind_fanout_size = dccp_bind_fanout_size;
220
221 /* Bind fanout */
222 dccps->dccps_bind_fanout = kmem_zalloc(dccps->dccps_bind_fanout_size *
223 sizeof (dccp_df_t), KM_SLEEP);
224 for (i = 0; i < dccps->dccps_bind_fanout_size; i++) {
225 mutex_init(&dccps->dccps_bind_fanout[i].df_lock, NULL,
226 MUTEX_DEFAULT, NULL);
227 }
228
229 /* Tunable properties */
230 arrsz = dccp_propinfo_count * sizeof (mod_prop_info_t);
231 dccps->dccps_propinfo_tbl = kmem_alloc(arrsz, KM_SLEEP);
232 if (dccps->dccps_propinfo_tbl == NULL) {
233 kmem_free(dccps, sizeof (*dccps));
234 return (NULL);
235 }
236 bcopy(dccp_propinfo_tbl, dccps->dccps_propinfo_tbl, arrsz);
237
238 /* Allocate per netstack cpu stats */
239 mutex_enter(&cpu_lock);
240 dccps->dccps_sc_cnt = MAX(ncpus, boot_ncpus);
241 mutex_exit(&cpu_lock);
242
243 dccps->dccps_sc = kmem_zalloc(max_ncpus * sizeof (dccp_stats_cpu_t *),
244 KM_SLEEP);
245 for (i = 0; i < dccps->dccps_sc_cnt; i++) {
246 dccps->dccps_sc[i] = kmem_zalloc(sizeof (dccp_stats_cpu_t),
247 KM_SLEEP);
248 }
249
250 /* Driver major number */
251 major = mod_name_to_major(INET_NAME);
252 error = ldi_ident_from_major(major, &dccps->dccps_ldi_ident);
253 ASSERT(error == 0);
254
255 return (dccps);
256 }
257
258 /*
259 * Destroy this DCCP netstack instance.
260 */
261 static void
262 dccp_stack_fini(netstackid_t stackid, void *arg)
263 {
264 dccp_stack_t *dccps = (dccp_stack_t *)arg;
265 int i;
266
267 /* Cpu stats */
268 for (i = 0; i < dccps->dccps_sc_cnt; i++) {
269 kmem_free(dccps->dccps_sc[i], sizeof (dccp_stats_cpu_t));
270 }
271 kmem_free(dccps->dccps_sc, max_ncpus * sizeof (dccp_stats_cpu_t *));
272
273 /* Tunable properties */
274 kmem_free(dccps->dccps_propinfo_tbl,
275 dccp_propinfo_count * sizeof (mod_prop_info_t));
276 dccps->dccps_propinfo_tbl = NULL;
277
278 /* Bind fanout */
279 for (i = 0; i < dccps->dccps_bind_fanout_size; i++) {
280 ASSERT(dccps->dccps_bind_fanout[i].df_dccp == NULL);
281 mutex_destroy(&dccps->dccps_bind_fanout[i].df_lock);
282 }
283 kmem_free(dccps->dccps_bind_fanout, dccps->dccps_bind_fanout_size *
284 sizeof (dccp_df_t));
285 dccps->dccps_bind_fanout = NULL;
286
287 kmem_free(dccps, sizeof (*dccps));
288 }
289
290 /* /dev/dccp */
291 static int
292 dccp_openv4(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
293 {
294 cmn_err(CE_NOTE, "dccp.c: dccp_openv4\n");
295
296 return (dccp_open(q, devp, flag, sflag, credp, B_FALSE));
297 }
298
299 /* /dev/dccp6 */
300 static int
301 dccp_openv6(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
302 {
303 cmn_err(CE_NOTE, "dccp.c: dccp_openv6\n");
304
305 return (dccp_open(q, devp, flag, sflag, credp, B_TRUE));
306 }
307
308 /*
309 * Common open function for v4 and v6 devices.
310 */
311 static int
312 dccp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp,
313 boolean_t isv6)
314 {
315 conn_t *connp;
316 dccp_t *dccp;
317 vmem_t *minor_arena;
318 dev_t conn_dev;
319 boolean_t issocket;
320 int error;
321
322 cmn_err(CE_NOTE, "dccp.c: dccp_open");
323
324 /* If the stream is already open, return immediately */
325 if (q->q_ptr != NULL) {
326 return (0);
327 }
328
329 if (sflag == MODOPEN) {
330 return (EINVAL);
331 }
332
333 if ((ip_minor_arena_la != NULL) && (flag & SO_SOCKSTR) &&
334 ((conn_dev = inet_minor_alloc(ip_minor_arena_la)) != 0)) {
335 minor_arena = ip_minor_arena_la;
336 } else {
337 /*
338 * Either minor numbers in the large arena were exhausted
339 * or a non socket application is doing the open.
340 * Try to allocate from the small arena.
341 */
342 if ((conn_dev = inet_minor_alloc(ip_minor_arena_sa)) == 0) {
343 return (EBUSY);
344 }
345 minor_arena = ip_minor_arena_sa;
346 }
347
348 ASSERT(minor_arena != NULL);
349
350 *devp = makedevice(getmajor(*devp), (minor_t)conn_dev);
351
352 if (flag & SO_FALLBACK) {
353 /*
354 * Non streams socket needs a stream to fallback to.
355 */
356 RD(q)->q_ptr = (void *)conn_dev;
357 WR(q)->q_qinfo = &dccp_fallback_sock_winit;
358 WR(q)->q_ptr = (void *)minor_arena;
359 qprocson(q);
360 return (0);
361 } else if (flag & SO_ACCEPTOR) {
362 q->q_qinfo = &dccp_acceptor_rinit;
363 /*
364 * The conn_dev and minor_arena will be subsequently used by
365 * dccp_tli_accept() and dccp_tpi_close_accept() to figure out
366 * the minor device number for this connection from the q_ptr.
367 */
368 RD(q)->q_ptr = (void *)conn_dev;
369 WR(q)->q_qinfo = &dccp_acceptor_winit;
370 WR(q)->q_ptr = (void *)minor_arena;
371 qprocson(q);
372 return (0);
373 }
374
375
376 issocket = flag & SO_SOCKSTR;
377 connp = dccp_create_common(credp, isv6, issocket, &error);
378 if (connp == NULL) {
379 inet_minor_free(minor_arena, conn_dev);
380 q->q_ptr = WR(q)->q_ptr = NULL;
381 return (error);
382 }
383
384 connp->conn_rq = q;
385 connp->conn_wq = WR(q);
386 q->q_ptr = WR(q)->q_ptr = connp;
387
388 connp->conn_dev = conn_dev;
389 connp->conn_minor_arena = minor_arena;
390
391 ASSERT(q->q_qinfo == &dccp_rinitv4 || q->q_qinfo == &dccp_rinitv6);
392 ASSERT(WR(q)->q_qinfo == &dccp_winit);
393
394 dccp = connp->conn_dccp;
395
396 if (issocket) {
397 WR(q)->q_qinfo = &dccp_sock_winit;
398 } else {
399 #ifdef _ILP32
400 dccp->dccp_acceptor_id = (t_uscalar_t)RD(q);
401 #else
402 dccp->dccp_acceptor_id = conn_dev;
403 #endif /* _ILP32 */
404 }
405
406 /*
407 * Put the ref for DCCP. Ref for IP was already put
408 * by ipcl_conn_create. Also Make the conn_t globally
409 * visible to walkers.
410 */
411 mutex_enter(&connp->conn_lock);
412 CONN_INC_REF_LOCKED(connp);
413 ASSERT(connp->conn_ref == 2);
414 connp->conn_state_flags &= ~CONN_INCIPIENT;
415 mutex_exit(&connp->conn_lock);
416
417 qprocson(q);
418
419 return (0);
420 }
421
422 /*
423 * IXA notify
424 */
425 static void
426 dccp_notify(void *arg, ip_xmit_attr_t *ixa, ixa_notify_type_t ntype,
427 ixa_notify_arg_t narg)
428 {
429 cmn_err(CE_NOTE, "dccp.c: dccp_notify");
430 }
431
432 /*
433 * Build the template headers.
434 */
435 int
436 dccp_build_hdrs(dccp_t *dccp)
437 {
438 dccp_stack_t *dccps = dccp->dccp_dccps;
439 conn_t *connp = dccp->dccp_connp;
440 dccpha_t *dccpha;
441 uint32_t cksum;
442 char buf[DCCP_MAX_HDR_LENGTH];
443 uint_t buflen;
444 uint_t ulplen = 12;
445 uint_t extralen = 0;
446 int error;
447
448 cmn_err(CE_NOTE, "dccp.c: dccp_build_hdrs");
449
450 buflen = connp->conn_ht_ulp_len;
451 if (buflen != 0) {
452 cmn_err(CE_NOTE, "buflen != 0");
453 bcopy(connp->conn_ht_ulp, buf, buflen);
454 extralen -= buflen - ulplen;
455 ulplen = buflen;
456 }
457
458 mutex_enter(&connp->conn_lock);
459 error = conn_build_hdr_template(connp, ulplen, extralen,
460 &connp->conn_laddr_v6, &connp->conn_faddr_v6, connp->conn_flowinfo);
461 mutex_exit(&connp->conn_lock);
462 if (error != 0) {
463 cmn_err(CE_NOTE, "conn_build_hdr_template failed");
464 return (error);
465 }
466
467 dccpha = (dccpha_t *)connp->conn_ht_ulp;
468 dccp->dccp_dccpha = dccpha;
469
470 if (buflen != 0) {
471 bcopy(buf, connp->conn_ht_ulp, buflen);
472 } else {
473 dccpha->dha_sum = 0;
474 dccpha->dha_lport = connp->conn_lport;
475 dccpha->dha_fport = connp->conn_fport;
476 }
477
478 cksum = sizeof (dccpha_t) + connp->conn_sum;
479 cksum = (cksum >> 16) + (cksum & 0xFFFF);
480 dccpha->dha_sum = htons(cksum);
481 dccpha->dha_offset = 7;
482 dccpha->dha_x = 1;
483
484 if (connp->conn_ipversion == IPV4_VERSION) {
485 dccp->dccp_ipha = (ipha_t *)connp->conn_ht_iphc;
486 } else {
487 dccp->dccp_ip6h = (ip6_t *)connp->conn_ht_iphc;
488 }
489
490 /* XXX */
491
492 return (0);
493 }
494
495 /*
496 * DCCP write service routine.
497 */
498 static void
499 dccp_wsrv(queue_t *q)
500 {
501 /* XXX:DCCP */
502 }
503
504 /*
505 * Common create function for streams and sockets.
506 */
507 conn_t *
508 dccp_create_common(cred_t *credp, boolean_t isv6, boolean_t issocket,
509 int *errorp)
510 {
511 conn_t *connp;
512 dccp_t *dccp;
513 dccp_stack_t *dccps;
514 netstack_t *ns;
515 squeue_t *sqp;
516 zoneid_t zoneid;
517
518 cmn_err(CE_NOTE, "dccp.c: dccp_create_common\n");
519
520 ASSERT(errorp != NULL);
521
522 *errorp = secpolicy_basic_net_access(credp);
523 if (*errorp != 0) {
524 return (NULL);
525 }
526
527 /*
528 * Find the right netstack
529 */
530 ns = netstack_find_by_cred(credp);
531 ASSERT(ns != NULL);
532 dccps = ns->netstack_dccp;
533 ASSERT(dccps != NULL);
534
535 /*
536 * XXX
537 */
538 if (ns->netstack_stackid != GLOBAL_NETSTACKID) {
539 zoneid = GLOBAL_ZONEID;
540 } else {
541 zoneid = crgetzoneid(credp);
542 }
543
544 sqp = IP_SQUEUE_GET((uint_t)gethrtime());
545 connp = (conn_t *)dccp_get_conn(sqp, dccps);
546 netstack_rele(dccps->dccps_netstack);
547 if (connp == NULL) {
548 *errorp = ENOSR;
549 return (NULL);
550 }
551 ASSERT(connp->conn_ixa->ixa_protocol == connp->conn_proto);
552
553 connp->conn_sqp = sqp;
554 connp->conn_initial_sqp = connp->conn_sqp;
555 connp->conn_ixa->ixa_sqp = connp->conn_sqp;
556 dccp = connp->conn_dccp;
557
558 /* Setting flags for ip output */
559 connp->conn_ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
560 IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO;
561
562 ASSERT(connp->conn_proto == IPPROTO_DCCP);
563 ASSERT(connp->conn_dccp == dccp);
564 ASSERT(dccp->dccp_connp == connp);
565
566 if (isv6) {
567 connp->conn_ixa->ixa_src_preferences = IPV6_PREFER_SRC_DEFAULT;
568 connp->conn_ipversion = IPV6_VERSION;
569 connp->conn_family = AF_INET6;
570 /* XXX mms, ttl */
571 } else {
572 connp->conn_ipversion = IPV4_VERSION;
573 connp->conn_family = AF_INET;
574 /* XXX mms, ttl */
575 }
576 connp->conn_xmit_ipp.ipp_unicast_hops = connp->conn_default_ttl;
577
578 crhold(credp);
579 connp->conn_cred = credp;
580 connp->conn_cpid = curproc->p_pid;
581 connp->conn_open_time = ddi_get_lbolt64();
582
583 ASSERT(!(connp->conn_ixa->ixa_free_flags & IXA_FREE_CRED));
584 connp->conn_ixa->ixa_cred = credp;
585 connp->conn_ixa->ixa_cpid = connp->conn_cpid;
586
587 connp->conn_zoneid = zoneid;
588 connp->conn_zone_is_global = (crgetzoneid(credp) == GLOBAL_ZONEID);
589 connp->conn_ixa->ixa_zoneid = zoneid;
590 connp->conn_mlp_type = mlptSingle;
591
592
593 dccp->dccp_dccps = dccps;
594 dccp->dccp_state = DCCPS_CLOSED;
595
596 ASSERT(connp->conn_netstack == dccps->dccps_netstack);
597 ASSERT(dccp->dccp_dccps == dccps);
598
599 /* XXX rcvbuf, sndbuf etc */
600
601 connp->conn_so_type = SOCK_STREAM;
602
603 SOCK_CONNID_INIT(dccp->dccp_connid);
604 dccp_init_values(dccp, NULL);
605
606 return (connp);
607 }
608
609 /*
610 * Common close function for streams and sockets.
611 */
612 void
613 dccp_close_common(conn_t *connp, int flags)
614 {
615 dccp_t *dccp = connp->conn_dccp;
616 boolean_t conn_ioctl_cleanup_reqd = B_FALSE;
617
618 ASSERT(connp->conn_ref >= 2);
619
620 mutex_enter(&connp->conn_lock);
621 connp->conn_state_flags |= CONN_CLOSING;
622 if (connp->conn_oper_pending_ill != NULL) {
623 conn_ioctl_cleanup_reqd = B_TRUE;
624 }
625
626 CONN_INC_REF_LOCKED(connp);
627 mutex_exit(&connp->conn_lock);
628
629 //ipcl_conn_destroy(connp);
630 }
631
632 /*
633 * Common bind function.
634 */
635 int
636 dccp_do_bind(conn_t *connp, struct sockaddr *sa, socklen_t len, cred_t *cr,
637 boolean_t bind_to_req_port_only)
638 {
639 dccp_t *dccp = connp->conn_dccp;
640 int error;
641
642 cmn_err(CE_NOTE, "dccp.c: dccp_do_bind");
643
644 if (dccp->dccp_state >= DCCPS_BOUND) {
645 if (connp->conn_debug) {
646 (void) strlog(DCCP_MOD_ID, 0, 1, SL_ERROR|SL_TRACE,
647 "dccp_bind: bad state, %d", dccp->dccp_state);
648 }
649 return (-TOUTSTATE);
650 }
651
652 error = dccp_bind_check(connp, sa, len, cr, bind_to_req_port_only);
653 if (error != 0) {
654 return (error);
655 }
656
657 ASSERT(dccp->dccp_state == DCCPS_LISTEN);
658 /* XXX dccp_conn_req_max = 0 */
659
660 return (0);
661 }
662
663 /*
664 * Common unbind function.
665 */
666 int
667 dccp_do_unbind(conn_t *connp)
668 {
669 dccp_t *dccp = connp->conn_dccp;
670
671 cmn_err(CE_NOTE, "dccp.c: dccp_do_unbind");
672
673 switch (dccp->dccp_state) {
674 case DCCPS_BOUND:
675 case DCCPS_LISTEN:
676 break;
677 default:
678 return (-TOUTSTATE);
679 }
680
681 /* XXX:DCCP */
682
683 return (0);
684 }
685
686 /*
687 * Common listen function.
688 */
689 int
690 dccp_do_listen(conn_t *connp, struct sockaddr *sa, socklen_t len,
691 int backlog, cred_t *cr, boolean_t bind_to_req_port_only)
692 {
693 dccp_t *dccp = connp->conn_dccp;
694 dccp_stack_t *dccps = dccp->dccp_dccps;
695 int32_t oldstate;
696 int error;
697
698 cmn_err(CE_NOTE, "dccp.c: dccp_do_listen");
699
700 /* All Solaris components should pass a cred for this operation */
701 ASSERT(cr != NULL);
702
703 if (dccp->dccp_state >= DCCPS_BOUND) {
704
705 if ((dccp->dccp_state == DCCPS_BOUND ||
706 dccp->dccp_state == DCCPS_LISTEN) && backlog > 0) {
707 goto do_listen;
708 }
709 cmn_err(CE_NOTE, "DCCPS_BOUND, bad state");
710
711 if (connp->conn_debug) {
712 (void) strlog(DCCP_MOD_ID, 0, 1, SL_ERROR|SL_TRACE,
713 "dccp_listen: bad state, %d", dccp->dccp_state);
714 }
715 return (-TOUTSTATE);
716 } else {
717 if (sa == NULL) {
718 sin6_t addr;
719 sin6_t *sin6;
720 sin_t *sin;
721
722 ASSERT(IPCL_IS_NONSTR(connp));
723
724 if (connp->conn_family == AF_INET) {
725 len = sizeof (sin_t);
726 sin = (sin_t *)&addr;
727 *sin = sin_null;
728 sin->sin_family = AF_INET;
729 } else {
730 ASSERT(connp->conn_family == AF_INET6);
731
732 len = sizeof (sin6_t);
733 sin6 = (sin6_t *)&addr;
734 *sin6 = sin6_null;
735 sin6->sin6_family = AF_INET6;
736 }
737
738 sa = (struct sockaddr *)&addr;
739 }
740
741 error = dccp_bind_check(connp, sa, len, cr,
742 bind_to_req_port_only);
743 if (error != 0) {
744 cmn_err(CE_NOTE, "dccp_bind_check failed");
745 return (error);
746 }
747 /* Fall through and do the fanout insertion */
748 }
749
750 do_listen:
751 ASSERT(dccp->dccp_state == DCCPS_BOUND ||
752 dccp->dccp_state == DCCPS_LISTEN);
753
754 /* XXX backlog */
755
756 connp->conn_recv = dccp_input_listener_unbound;
757
758 /* Insert into the classifier table */
759 error = ip_laddr_fanout_insert(connp);
760 if (error != 0) {
761 /* Error - undo the bind */
762 oldstate = dccp->dccp_state;
763 dccp->dccp_state = DCCPS_CLOSED;
764
765 connp->conn_bound_addr_v6 = ipv6_all_zeros;
766
767 connp->conn_laddr_v6 = ipv6_all_zeros;
768 connp->conn_saddr_v6 = ipv6_all_zeros;
769 connp->conn_ports = 0;
770
771 if (connp->conn_anon_port) {
772 zone_t *zone;
773
774 zone = crgetzone(cr);
775 connp->conn_anon_port = B_FALSE;
776 (void) tsol_mlp_anon(zone, connp->conn_mlp_type,
777 connp->conn_proto, connp->conn_lport, B_FALSE);
778 }
779 connp->conn_mlp_type = mlptSingle;
780
781 /* XXX dccp_bind_hash_remove */
782
783 return (error);
784 } else {
785 /* XXX connection limits */
786 }
787
788 return (error);
789 }
790
791 /*
792 * Common connect function.
793 */
794 int
795 dccp_do_connect(conn_t *connp, const struct sockaddr *sa, socklen_t len,
796 cred_t *cr, pid_t pid)
797 {
798 dccp_t *dccp = connp->conn_dccp;
799 dccp_stack_t *dccps = dccp->dccp_dccps;
800 ip_xmit_attr_t *ixa = connp->conn_ixa;
801 mblk_t *req_mp;
802 sin_t *sin = (sin_t *)sa;
803 sin6_t *sin6 = (sin6_t *)sa;
804 ipaddr_t *dstaddrp;
805 in_port_t dstport;
806 uint_t srcid;
807 int32_t oldstate;
808 int error;
809
810 cmn_err(CE_NOTE, "dccp.c: dccp_do_connect");
811
812 oldstate = dccp->dccp_state;
813
814 switch (len) {
815 case sizeof (sin_t):
816 sin = (sin_t *)sa;
817 if (sin->sin_port == 0) {
818 return (-TBADADDR);
819 }
820 if (connp->conn_ipv6_v6only) {
821 return (EAFNOSUPPORT);
822 }
823 break;
824
825 case sizeof (sin6_t):
826 sin6 = (sin6_t *)sa;
827 if (sin6->sin6_port == 0) {
828 return (-TBADADDR);
829 }
830 break;
831
832 default:
833 return (EINVAL);
834 }
835
836 if (connp->conn_family == AF_INET6 &&
837 connp->conn_ipversion == IPV6_VERSION &&
838 IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
839 if (connp->conn_ipv6_v6only) {
840 return (EADDRNOTAVAIL);
841 }
842
843 connp->conn_ipversion = IPV4_VERSION;
844 }
845
846 switch (dccp->dccp_state) {
847 case DCCPS_LISTEN:
848 if (IPCL_IS_NONSTR(connp)) {
849 return (EOPNOTSUPP);
850 }
851
852 case DCCPS_CLOSED:
853 /* XXX */
854 break;
855
856 default:
857 return (-TOUTSTATE);
858 }
859
860 if (connp->conn_cred != cr) {
861 crhold(cr);
862 crfree(connp->conn_cred);
863 connp->conn_cred = cr;
864 }
865 connp->conn_cpid = pid;
866
867 /* Cache things in the ixa without any refhold */
868 ASSERT(!(ixa->ixa_free_flags & IXA_FREE_CRED));
869 ixa->ixa_cred = cr;
870 ixa->ixa_cpid = pid;
871
872 if (is_system_labeled()) {
873 ip_xmit_attr_restore_tsl(ixa, ixa->ixa_cred);
874 }
875
876 if (connp->conn_family == AF_INET6) {
877 if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
878 error = dccp_connect_ipv6(dccp, &sin6->sin6_addr,
879 sin6->sin6_port, sin6->sin6_flowinfo,
880 sin6->__sin6_src_id, sin6->sin6_scope_id);
881 } else {
882 /*
883 * Destination adress is mapped IPv6 address.
884 * Source bound address should be unspecified or
885 * IPv6 mapped address as well.
886 */
887 if (!IN6_IS_ADDR_UNSPECIFIED(
888 &connp->conn_bound_addr_v6) &&
889 !IN6_IS_ADDR_V4MAPPED(&connp->conn_bound_addr_v6)) {
890 return (EADDRNOTAVAIL);
891 }
892
893 dstaddrp = &V4_PART_OF_V6((sin6->sin6_addr));
894 dstport = sin6->sin6_port;
895 srcid = sin6->__sin6_src_id;
896 error = dccp_connect_ipv4(dccp, dstaddrp, dstport,
897 srcid);
898 }
899 } else {
900 dstaddrp = &sin->sin_addr.s_addr;
901 dstport = sin->sin_port;
902 srcid = 0;
903 error = dccp_connect_ipv4(dccp, dstaddrp, dstport, srcid);
904 }
905
906 if (error != 0) {
907 goto connect_failed;
908 }
909
910 /* XXX cluster */
911
912 DCCPS_BUMP_MIB(dccps, dccpActiveOpens);
913 dccp->dccp_active_open = 1;
914
915 DTRACE_DCCP6(state__change, void, NULL, ip_xmit_attr_t *,
916 connp->conn_ixa, void, NULL, dccp_t *, dccp, void, NULL,
917 int32_t, DCCPS_BOUND);
918
919 req_mp = dccp_generate_request(connp);
920 if (req_mp != NULL) {
921 /*
922 * We must bump the generation before sending the request
923 * to ensure that we use the right generation in case
924 * this thread issues a "connected" up call.
925 */
926 SOCK_CONNID_BUMP(dccp->dccp_connid);
927
928 DTRACE_DCCP5(connect__request, mblk_t *, NULL,
929 ip_xmit_attr_t *, connp->conn_ixa,
930 void_ip_t *, req_mp->b_rptr, dccp_t *, dccp,
931 dccpha_t *,
932 &req_mp->b_rptr[connp->conn_ixa->ixa_ip_hdr_length]);
933
934 dccp_send_data(dccp, req_mp);
935 }
936
937 return (0);
938
939 connect_failed:
940 cmn_err(CE_NOTE, "dccp_do_connect failed");
941
942 connp->conn_faddr_v6 = ipv6_all_zeros;
943 connp->conn_fport = 0;
944 dccp->dccp_state = oldstate;
945
946 return (error);
947 }
948
949 /*
950 * Init values of a connection.
951 */
952 void
953 dccp_init_values(dccp_t *dccp, dccp_t *parent)
954 {
955 conn_t *connp = dccp->dccp_connp;
956 dccp_stack_t *dccps = dccp->dccp_dccps;
957
958 connp->conn_mlp_type = mlptSingle;
959 }
960
961 void *
962 dccp_get_conn(void *arg, dccp_stack_t *dccps)
963 {
964 dccp_t *dccp = NULL;
965 conn_t *connp;
966 squeue_t *sqp = (squeue_t *)arg;
967 netstack_t *ns;
968
969 /* XXX timewait */
970
971 connp = ipcl_conn_create(IPCL_DCCPCONN, KM_NOSLEEP,
972 dccps->dccps_netstack);
973 if (connp == NULL) {
974 return (NULL);
975 }
976
977 dccp = connp->conn_dccp;
978 dccp->dccp_dccps = dccps;
979
980 /* List of features being negotated */
981 list_create(&dccp->dccp_features, sizeof (dccp_feature_t),
982 offsetof(dccp_feature_t, df_next));
983
984 connp->conn_recv = dccp_input_data;
985 connp->conn_recvicmp = dccp_icmp_input;
986 connp->conn_verifyicmp = dccp_verifyicmp;
987
988 connp->conn_ixa->ixa_notify = dccp_notify;
989 connp->conn_ixa->ixa_notify_cookie = dccp;
990
991 return ((void *)connp);
992 }
993
994 /*
995 * IPv4 connect.
996 */
997 static int
998 dccp_connect_ipv4(dccp_t *dccp, ipaddr_t *dstaddrp, in_port_t dstport,
999 uint_t srcid)
1000 {
1001 conn_t *connp = dccp->dccp_connp;
1002 dccp_stack_t *dccps = dccp->dccp_dccps;
1003 ipaddr_t dstaddr = *dstaddrp;
1004 uint16_t lport;
1005 int error;
1006
1007 cmn_err(CE_NOTE, "dccp.c: dccp_connect_ipv4");
1008
1009 ASSERT(connp->conn_ipversion == IPV4_VERSION);
1010
1011 if (dstaddr == INADDR_ANY) {
1012 dstaddr = htonl(INADDR_LOOPBACK);
1013 *dstaddrp = dstaddr;
1014 }
1015
1016 if (srcid != 0 && connp->conn_laddr_v4 == INADDR_ANY) {
1017 ip_srcid_find_id(srcid, &connp->conn_laddr_v6,
1018 IPCL_ZONEID(connp), dccps->dccps_netstack);
1019 connp->conn_saddr_v6 = connp->conn_laddr_v6;
1020 }
1021
1022 IN6_IPADDR_TO_V4MAPPED(dstaddr, &connp->conn_faddr_v6);
1023 connp->conn_fport = dstport;
1024
1025 if (dccp->dccp_state == DCCPS_CLOSED) {
1026 lport = dccp_update_next_port(dccps->dccps_next_port_to_try,
1027 dccp, B_TRUE);
1028 lport = dccp_bindi(dccp, lport, &connp->conn_laddr_v6, 0,
1029 B_TRUE, B_FALSE, B_FALSE);
1030
1031 if (lport == 0) {
1032 return (-TNOADDR);
1033 }
1034 }
1035
1036 error = dccp_set_destination(dccp);
1037 if (error != 0) {
1038 return (error);
1039 }
1040
1041 /*
1042 * Don't connect to oneself.
1043 */
1044 if (connp->conn_faddr_v4 == connp->conn_laddr_v4 &&
1045 connp->conn_fport == connp->conn_lport) {
1046 return (-TBADADDR);
1047 }
1048
1049 /* XXX state */
1050
1051 return (ipcl_conn_insert_v4(connp));
1052 }
1053
1054 /*
1055 * IPv6 connect.
1056 */
1057 static int
1058 dccp_connect_ipv6(dccp_t *dccp, in6_addr_t *dstaddrp, in_port_t dstport,
1059 uint32_t flowinfo, uint_t srcid, uint32_t scope_id)
1060 {
1061 cmn_err(CE_NOTE, "dccp.c: dccp_connect_ipv6");
1062
1063 return (0);
1064 }
1065
1066 /*
1067 * Set the ports via conn_connect and build the template
1068 * header.
1069 */
1070 int
1071 dccp_set_destination(dccp_t *dccp)
1072 {
1073 conn_t *connp = dccp->dccp_connp;
1074 dccp_stack_t *dccps = dccp->dccp_dccps;
1075 iulp_t uinfo;
1076 uint32_t flags;
1077 int error;
1078
1079 flags = IPDF_LSO | IPDF_ZCOPY;
1080 flags |= IPDF_UNIQUE_DCE;
1081
1082 mutex_enter(&connp->conn_lock);
1083 error = conn_connect(connp, &uinfo, flags);
1084 mutex_exit(&connp->conn_lock);
1085 if (error != 0) {
1086 cmn_err(CE_NOTE, "conn_connect failed");
1087 return (error);
1088 }
1089
1090 error = dccp_build_hdrs(dccp);
1091 if (error != 0) {
1092 cmn_err(CE_NOTE, "dccp_build_hdrs failed");
1093 return (error);
1094 }
1095
1096 /* XXX */
1097
1098 /* Initialise the ISS */
1099 dccp_iss_init(dccp);
1100
1101 mutex_enter(&connp->conn_lock);
1102 connp->conn_state_flags &= ~CONN_INCIPIENT;
1103 mutex_exit(&connp->conn_lock);
1104
1105 return (0);
1106 }
1107
1108 /*
1109 * Init the ISS.
1110 */
1111 static void
1112 dccp_iss_init(dccp_t *dccp)
1113 {
1114 cmn_err(CE_NOTE, "dccp.c: dccp_iss_init");
1115
1116 dccp->dccp_iss += gethrtime();
1117 }