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/isa_defs.h>
45 #include <sys/tsol/label.h>
46 #include <sys/tsol/tnet.h>
47 #include <inet/kstatcom.h>
48 #include <inet/snmpcom.h>
49
50 #include <sys/cmn_err.h>
51
52 #include "dccp_impl.h"
53 #include "dccp_stack.h"
54
55 /* Setable in /etc/system */
56 uint_t dccp_bind_fanout_size = DCCP_BIND_FANOUT_SIZE;
57
58 static void dccp_notify(void *, ip_xmit_attr_t *, ixa_notify_type_t,
59 ixa_notify_arg_t);
60
61 /* Functions to register netstack */
62 static void *dccp_stack_init(netstackid_t, netstack_t *);
63 static void dccp_stack_fini(netstackid_t, void *);
64
65 static int dccp_openv4(queue_t *, dev_t *, int, int, cred_t *);
66 static int dccp_openv6(queue_t *, dev_t *, int, int, cred_t *);
67
68 /* Write service routine */
69 static void dccp_wsrv(queue_t *);
70
71 /* Connection related functions */
72 static int dccp_connect_ipv4(dccp_t *, ipaddr_t *, in_port_t, uint_t);
73 static int dccp_connect_ipv6(dccp_t *, in6_addr_t *, in_port_t, uint32_t,
74 uint_t, uint32_t);
75
76 struct module_info dccp_rinfo = {
77 DCCP_MOD_ID, DCCP_MOD_NAME, 0, INFPSZ, DCCP_RECV_HIWATER,
78 DCCP_RECV_LOWATER
79 };
80
81 static struct module_info dccp_winfo = {
82 DCCP_MOD_ID, DCCP_MOD_NAME, 0, INFPSZ, 127, 16
83 };
84
85 /*
86 * Queue information structure with DCCP entry points.
87 */
88 struct qinit dccp_rinitv4 = {
89 NULL, (pfi_t)dccp_rsrv, dccp_openv4, dccp_tpi_close, NULL, &dccp_rinfo
90 };
91
92 struct qinit dccp_rinitv6 = {
93 NULL, (pfi_t)dccp_rsrv, dccp_openv6, dccp_tpi_close, NULL, &dccp_rinfo
94 };
95
96 struct qinit dccp_winit = {
97 (pfi_t)dccp_wput, (pfi_t)dccp_wsrv, NULL, NULL, NULL, &dccp_winfo
98 };
99
100 /* AF_INET /dev/dccp */
101 struct streamtab dccpinfov4 = {
102 &dccp_rinitv4, &dccp_winit
103 };
104
105 /* AF_INET6 /dev/dccp6 */
106 struct streamtab dccpinfov6 = {
107 &dccp_rinitv6, &dccp_winit
108 };
109
110 /*
111 * Tunables.
112 */
113 extern mod_prop_info_t dccp_propinfo_tbl[];
114 extern int dccp_propinfo_count;
115
116 /*
117 * Register DCCP netstack.
118 */
119 void
120 dccp_ddi_g_init(void)
121 {
122 netstack_register(NS_DCCP, dccp_stack_init, NULL, dccp_stack_fini);
123 }
124
125 #define INET_NAME "ip"
126
127 /*
128 * Initialize the DCCP stack instance.
129 */
130 static void *
131 dccp_stack_init(netstackid_t stackid, netstack_t *ns)
132 {
133 dccp_stack_t *dccps;
134 major_t major;
135 size_t arrsz;
136 int error;
137 int i;
138
139 dccps = kmem_zalloc(sizeof (*dccps), KM_SLEEP);
140 if (dccps == NULL) {
141 return (NULL);
142 }
143 dccps->dccps_netstack = ns;
144
145 /* Ports */
146 mutex_init(&dccps->dccps_epriv_port_lock, NULL, MUTEX_DEFAULT, NULL);
147 dccps->dccps_num_epriv_ports = DCCP_NUM_EPRIV_PORTS;
148 dccps->dccps_epriv_ports[0] = ULP_DEF_EPRIV_PORT1;
149 dccps->dccps_epriv_ports[1] = ULP_DEF_EPRIV_PORT2;
150 dccps->dccps_min_anonpriv_port = 512;
151
152 dccps->dccps_bind_fanout_size = dccp_bind_fanout_size;
153
154 /* Bind fanout */
155 dccps->dccps_bind_fanout = kmem_zalloc(dccps->dccps_bind_fanout_size *
156 sizeof (dccp_df_t), KM_SLEEP);
157 for (i = 0; i < dccps->dccps_bind_fanout_size; i++) {
158 mutex_init(&dccps->dccps_bind_fanout[i].df_lock, NULL,
159 MUTEX_DEFAULT, NULL);
160 }
161
162 /* Tunable properties */
163 arrsz = dccp_propinfo_count * sizeof (mod_prop_info_t);
164 dccps->dccps_propinfo_tbl = kmem_alloc(arrsz, KM_SLEEP);
165 if (dccps->dccps_propinfo_tbl == NULL) {
166 kmem_free(dccps, sizeof (*dccps));
167 return (NULL);
168 }
169 bcopy(dccp_propinfo_tbl, dccps->dccps_propinfo_tbl, arrsz);
170
171 /* Allocate per netstack cpu stats */
172 mutex_enter(&cpu_lock);
173 dccps->dccps_sc_cnt = MAX(ncpus, boot_ncpus);
174 mutex_exit(&cpu_lock);
175
176 dccps->dccps_sc = kmem_zalloc(max_ncpus * sizeof (dccp_stats_cpu_t *),
177 KM_SLEEP);
178 for (i = 0; i < dccps->dccps_sc_cnt; i++) {
179 dccps->dccps_sc[i] = kmem_zalloc(sizeof (dccp_stats_cpu_t),
180 KM_SLEEP);
181 }
182
183 /* Driver major number */
184 major = mod_name_to_major(INET_NAME);
185 error = ldi_ident_from_major(major, &dccps->dccps_ldi_ident);
186 ASSERT(error == 0);
187
188 return (dccps);
189 }
190
191 /*
192 * Destroy the DCCP stack instance.
193 */
194 void
195 dccp_ddi_g_destroy(void)
196 {
197 cmn_err(CE_NOTE, "dccp.c: dccp_ddi_g_destroy\n");
198
199 netstack_unregister(NS_DCCP);
200 }
201
202 static void
203 dccp_stack_fini(netstackid_t stackid, void *arg)
204 {
205 dccp_stack_t *dccps = (dccp_stack_t *)arg;
206 int i;
207
208 /* Cpu stats */
209 for (i = 0; i < dccps->dccps_sc_cnt; i++) {
210 kmem_free(dccps->dccps_sc[i], sizeof (dccp_stats_cpu_t));
211 }
212 kmem_free(dccps->dccps_sc, max_ncpus * sizeof (dccp_stats_cpu_t *));
213
214 /* Tunable properties */
215 kmem_free(dccps->dccps_propinfo_tbl,
216 dccp_propinfo_count * sizeof (mod_prop_info_t));
217 dccps->dccps_propinfo_tbl = NULL;
218
219 /* Bind fanout */
220 for (i = 0; i < dccps->dccps_bind_fanout_size; i++) {
221 ASSERT(dccps->dccps_bind_fanout[i].df_dccp == NULL);
222 mutex_destroy(&dccps->dccps_bind_fanout[i].df_lock);
223 }
224 kmem_free(dccps->dccps_bind_fanout, dccps->dccps_bind_fanout_size *
225 sizeof (dccp_df_t));
226 dccps->dccps_bind_fanout = NULL;
227
228 kmem_free(dccps, sizeof (*dccps));
229 }
230
231 /* /dev/dccp */
232 static int
233 dccp_openv4(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
234 {
235 cmn_err(CE_NOTE, "dccp.c: dccp_openv4\n");
236
237 return (ENOTSUP);
238 }
239
240 /* /dev/dccp6 */
241 static int
242 dccp_openv6(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
243 {
244 cmn_err(CE_NOTE, "dccp.c: dccp_openv6\n");
245
246 return (ENOTSUP);
247 }
248
249 /*
250 * IXA notify
251 */
252 static void
253 dccp_notify(void *arg, ip_xmit_attr_t *ixa, ixa_notify_type_t ntype,
254 ixa_notify_arg_t narg)
255 {
256 cmn_err(CE_NOTE, "dccp.c: dccp_notify");
257 }
258
259 /*
260 * Build the template headers.
261 */
262 int
263 dccp_build_hdrs(dccp_t *dccp)
264 {
265 dccp_stack_t *dccps = dccp->dccp_dccps;
266 conn_t *connp = dccp->dccp_connp;
267 dccpha_t *dccpha;
268 uint32_t cksum;
269 char buf[DCCP_MAX_HDR_LENGTH];
270 uint_t buflen;
271 uint_t ulplen = 12;
272 uint_t extralen = 0;
273 int error;
274
275 cmn_err(CE_NOTE, "dccp.c: dccp_build_hdrs");
276
277 buflen = connp->conn_ht_ulp_len;
278 if (buflen != 0) {
279 cmn_err(CE_NOTE, "buflen != 0");
280 bcopy(connp->conn_ht_ulp, buf, buflen);
281 extralen -= buflen - ulplen;
282 ulplen = buflen;
283 }
284
285 mutex_enter(&connp->conn_lock);
286 error = conn_build_hdr_template(connp, ulplen, extralen,
287 &connp->conn_laddr_v6, &connp->conn_faddr_v6, connp->conn_flowinfo);
288 mutex_exit(&connp->conn_lock);
289 if (error != 0) {
290 cmn_err(CE_NOTE, "conn_build_hdr_template failed");
291 return (error);
292 }
293
294 dccpha = (dccpha_t *)connp->conn_ht_ulp;
295 dccp->dccp_dccpha = dccpha;
296
297 if (buflen != 0) {
298 bcopy(buf, connp->conn_ht_ulp, buflen);
299 } else {
300 dccpha->dha_sum = 0;
301 dccpha->dha_lport = connp->conn_lport;
302 dccpha->dha_fport = connp->conn_fport;
303 }
304
305 cksum = sizeof (dccpha_t) + connp->conn_sum;
306 cksum = (cksum >> 16) + (cksum & 0xFFFF);
307 dccpha->dha_sum = htons(cksum);
308 dccpha->dha_offset = 7;
309 dccpha->dha_x = 1;
310
311 return (0);
312 }
313
314 /*
315 * DCCP write service routine.
316 */
317 static void
318 dccp_wsrv(queue_t *q)
319 {
320 /* XXX:DCCP */
321 }
322
323 /*
324 * Common create function for streams and sockets.
325 */
326 conn_t *
327 dccp_create_common(cred_t *credp, boolean_t isv6, boolean_t issocket,
328 int *errorp)
329 {
330 conn_t *connp;
331 dccp_t *dccp;
332 dccp_stack_t *dccps;
333 netstack_t *ns;
334 squeue_t *sqp;
335 zoneid_t zoneid;
336
337 cmn_err(CE_NOTE, "dccp.c: dccp_create_common\n");
338
339 ASSERT(errorp != NULL);
340
341 *errorp = secpolicy_basic_net_access(credp);
342 if (*errorp != 0) {
343 return (NULL);
344 }
345
346 /*
347 * Find the right netstack
348 */
349 ns = netstack_find_by_cred(credp);
350 ASSERT(ns != NULL);
351 dccps = ns->netstack_dccp;
352 ASSERT(dccps != NULL);
353
354 /*
355 * XXX
356 */
357 if (ns->netstack_stackid != GLOBAL_NETSTACKID) {
358 zoneid = GLOBAL_ZONEID;
359 } else {
360 zoneid = crgetzoneid(credp);
361 }
362
363 sqp = IP_SQUEUE_GET((uint_t)gethrtime());
364 connp = (conn_t *)dccp_get_conn(sqp, dccps);
365 netstack_rele(dccps->dccps_netstack);
366 if (connp == NULL) {
367 *errorp = ENOSR;
368 return (NULL);
369 }
370 ASSERT(connp->conn_ixa->ixa_protocol == connp->conn_proto);
371
372 connp->conn_sqp = sqp;
373 connp->conn_initial_sqp = connp->conn_sqp;
374 connp->conn_ixa->ixa_sqp = connp->conn_sqp;
375 dccp = connp->conn_dccp;
376
377 /* Setting flags for ip output */
378 connp->conn_ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
379 IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO;
380
381 ASSERT(connp->conn_proto == IPPROTO_DCCP);
382 ASSERT(connp->conn_dccp == dccp);
383 ASSERT(dccp->dccp_connp == connp);
384
385 if (isv6) {
386 connp->conn_ixa->ixa_src_preferences = IPV6_PREFER_SRC_DEFAULT;
387 connp->conn_ipversion = IPV6_VERSION;
388 connp->conn_family = AF_INET6;
389 /* XXX mms, ttl */
390 } else {
391 connp->conn_ipversion = IPV4_VERSION;
392 connp->conn_family = AF_INET;
393 /* XXX mms, ttl */
394 }
395 connp->conn_xmit_ipp.ipp_unicast_hops = connp->conn_default_ttl;
396
397 crhold(credp);
398 connp->conn_cred = credp;
399 connp->conn_cpid = curproc->p_pid;
400 connp->conn_open_time = ddi_get_lbolt64();
401
402 ASSERT(!(connp->conn_ixa->ixa_free_flags & IXA_FREE_CRED));
403 connp->conn_ixa->ixa_cred = credp;
404 connp->conn_ixa->ixa_cpid = connp->conn_cpid;
405
406 connp->conn_zoneid = zoneid;
407 connp->conn_zone_is_global = (crgetzoneid(credp) == GLOBAL_ZONEID);
408 connp->conn_ixa->ixa_zoneid = zoneid;
409 connp->conn_mlp_type = mlptSingle;
410
411
412 dccp->dccp_dccps = dccps;
413 dccp->dccp_state = DCCPS_CLOSED;
414
415 ASSERT(connp->conn_netstack == dccps->dccps_netstack);
416 ASSERT(dccp->dccp_dccps == dccps);
417
418 /* XXX rcvbuf, sndbuf etc */
419
420 SOCK_CONNID_INIT(dccp->dccp_connid);
421 dccp_init_values(dccp, NULL);
422
423 return (connp);
424 }
425
426 /*
427 * Common close function for streams and sockets.
428 */
429 void
430 dccp_close_common(conn_t *connp)
431 {
432 dccp_t *dccp = connp->conn_dccp;
433 boolean_t conn_ioctl_cleanup_reqd = B_FALSE;
434
435 ASSERT(connp->conn_ref >= 2);
436
437 mutex_enter(&connp->conn_lock);
438 connp->conn_state_flags |= CONN_CLOSING;
439 if (connp->conn_oper_pending_ill != NULL) {
440 conn_ioctl_cleanup_reqd = B_TRUE;
441 }
442
443 CONN_INC_REF_LOCKED(connp);
444 mutex_exit(&connp->conn_lock);
445
446 //ipcl_conn_destroy(connp);
447 }
448
449 /*
450 * Common bind function.
451 */
452 int
453 dccp_do_bind(conn_t *connp, struct sockaddr *sa, socklen_t len, cred_t *cr,
454 boolean_t bind_to_req_port_only)
455 {
456 dccp_t *dccp = connp->conn_dccp;
457 int error;
458
459 cmn_err(CE_NOTE, "dccp.c: dccp_do_bind");
460
461 if (dccp->dccp_state >= DCCPS_BOUND) {
462 if (connp->conn_debug) {
463 (void) strlog(DCCP_MOD_ID, 0, 1, SL_ERROR|SL_TRACE,
464 "dccp_bind: bad state, %d", dccp->dccp_state);
465 }
466 return (-TOUTSTATE);
467 }
468
469 error = dccp_bind_check(connp, sa, len, cr, bind_to_req_port_only);
470 if (error != 0) {
471 return (error);
472 }
473
474 ASSERT(dccp->dccp_state == DCCPS_LISTEN);
475 /* XXX dccp_conn_req_max = 0 */
476
477 return (0);
478 }
479
480 /*
481 * Common unbind function.
482 */
483 int
484 dccp_do_unbind(conn_t *connp)
485 {
486 dccp_t *dccp = connp->conn_dccp;
487
488 cmn_err(CE_NOTE, "dccp.c: dccp_do_unbind");
489
490 switch (dccp->dccp_state) {
491 case DCCPS_BOUND:
492 case DCCPS_LISTEN:
493 break;
494 default:
495 return (-TOUTSTATE);
496 }
497
498 /* XXX:DCCP */
499
500 return (0);
501 }
502
503 /*
504 * Common listen function.
505 */
506 int
507 dccp_do_listen(conn_t *connp, struct sockaddr *sa, socklen_t len,
508 int backlog, cred_t *cr, boolean_t bind_to_req_port_only)
509 {
510 dccp_t *dccp = connp->conn_dccp;
511 dccp_stack_t *dccps = dccp->dccp_dccps;
512 int32_t oldstate;
513 int error;
514
515 cmn_err(CE_NOTE, "dccp.c: dccp_do_listen");
516
517 /* All Solaris components should pass a cred for this operation */
518 ASSERT(cr != NULL);
519
520 if (dccp->dccp_state >= DCCPS_BOUND) {
521
522 if ((dccp->dccp_state == DCCPS_BOUND ||
523 dccp->dccp_state == DCCPS_LISTEN) && backlog > 0) {
524 goto do_listen;
525 }
526 cmn_err(CE_NOTE, "DCCPS_BOUND, bad state");
527
528 if (connp->conn_debug) {
529 (void) strlog(DCCP_MOD_ID, 0, 1, SL_ERROR|SL_TRACE,
530 "dccp_listen: bad state, %d", dccp->dccp_state);
531 }
532 return (-TOUTSTATE);
533 } else {
534 if (sa == NULL) {
535 sin6_t addr;
536 sin6_t *sin6;
537 sin_t *sin;
538
539 ASSERT(IPCL_IS_NONSTR(connp));
540
541 if (connp->conn_family == AF_INET) {
542 len = sizeof (sin_t);
543 sin = (sin_t *)&addr;
544 *sin = sin_null;
545 sin->sin_family = AF_INET;
546 } else {
547 ASSERT(connp->conn_family == AF_INET6);
548
549 len = sizeof (sin6_t);
550 sin6 = (sin6_t *)&addr;
551 *sin6 = sin6_null;
552 sin6->sin6_family = AF_INET6;
553 }
554
555 sa = (struct sockaddr *)&addr;
556 }
557
558 error = dccp_bind_check(connp, sa, len, cr,
559 bind_to_req_port_only);
560 if (error != 0) {
561 cmn_err(CE_NOTE, "dccp_bind_check failed");
562 return (error);
563 }
564 /* Fall through and do the fanout insertion */
565 }
566
567 do_listen:
568 ASSERT(dccp->dccp_state == DCCPS_BOUND ||
569 dccp->dccp_state == DCCPS_LISTEN);
570
571 /* XXX backlog */
572
573 connp->conn_recv = dccp_input_listener_unbound;
574
575 /* Insert into the classifier table */
576 error = ip_laddr_fanout_insert(connp);
577 if (error != 0) {
578 /* Error - undo the bind */
579 oldstate = dccp->dccp_state;
580 dccp->dccp_state = DCCPS_CLOSED;
581
582 connp->conn_bound_addr_v6 = ipv6_all_zeros;
583
584 connp->conn_laddr_v6 = ipv6_all_zeros;
585 connp->conn_saddr_v6 = ipv6_all_zeros;
586 connp->conn_ports = 0;
587
588 if (connp->conn_anon_port) {
589 zone_t *zone;
590
591 zone = crgetzone(cr);
592 connp->conn_anon_port = B_FALSE;
593 (void) tsol_mlp_anon(zone, connp->conn_mlp_type,
594 connp->conn_proto, connp->conn_lport, B_FALSE);
595 }
596 connp->conn_mlp_type = mlptSingle;
597
598 /* XXX dccp_bind_hash_remove */
599
600 return (error);
601 } else {
602 /* XXX connection limits */
603 }
604
605 return (error);
606 }
607
608 /*
609 * Common connect function.
610 */
611 int
612 dccp_do_connect(conn_t *connp, const struct sockaddr *sa, socklen_t len,
613 cred_t *cr, pid_t pid)
614 {
615 dccp_t *dccp = connp->conn_dccp;
616 dccp_stack_t *dccps = dccp->dccp_dccps;
617 ip_xmit_attr_t *ixa = connp->conn_ixa;
618 sin_t *sin = (sin_t *)sa;
619 sin6_t *sin6 = (sin6_t *)sa;
620 ipaddr_t *dstaddrp;
621 in_port_t dstport;
622 int32_t oldstate;
623 uint_t srcid;
624 int error;
625
626 cmn_err(CE_NOTE, "dccp.c: dccp_do_connect");
627
628 oldstate = dccp->dccp_state;
629
630 switch (len) {
631 case sizeof (sin_t):
632 sin = (sin_t *)sa;
633 if (sin->sin_port == 0) {
634 return (-TBADADDR);
635 }
636 if (connp->conn_ipv6_v6only) {
637 return (EAFNOSUPPORT);
638 }
639 break;
640
641 case sizeof (sin6_t):
642 sin6 = (sin6_t *)sa;
643 if (sin6->sin6_port == 0) {
644 return (-TBADADDR);
645 }
646 break;
647
648 default:
649 return (EINVAL);
650 }
651
652 if (connp->conn_family == AF_INET6 &&
653 connp->conn_ipversion == IPV6_VERSION &&
654 IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
655 if (connp->conn_ipv6_v6only) {
656 return (EADDRNOTAVAIL);
657 }
658
659 connp->conn_ipversion = IPV4_VERSION;
660 }
661
662 switch (dccp->dccp_state) {
663 case DCCPS_LISTEN:
664 if (IPCL_IS_NONSTR(connp)) {
665 return (EOPNOTSUPP);
666 }
667
668 case DCCPS_CLOSED:
669 /* XXX */
670 break;
671
672 default:
673 return (-TOUTSTATE);
674 }
675
676 if (connp->conn_cred != cr) {
677 crhold(cr);
678 crfree(connp->conn_cred);
679 connp->conn_cred = cr;
680 }
681 connp->conn_cpid = pid;
682
683 ASSERT(!(ixa->ixa_free_flags & IXA_FREE_CRED));
684 ixa->ixa_cred = cr;
685 ixa->ixa_cpid = pid;
686
687 if (is_system_labeled()) {
688 ip_xmit_attr_restore_tsl(ixa, ixa->ixa_cred);
689 }
690
691 if (connp->conn_family == AF_INET6) {
692 if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
693 error = dccp_connect_ipv6(dccp, &sin6->sin6_addr,
694 sin6->sin6_port, sin6->sin6_flowinfo,
695 sin6->__sin6_src_id, sin6->sin6_scope_id);
696 } else {
697 /* XXX */
698 }
699 } else {
700 dstaddrp = &sin->sin_addr.s_addr;
701 dstport = sin->sin_port;
702 srcid = 0;
703 error = dccp_connect_ipv4(dccp, dstaddrp, dstport, srcid);
704 }
705
706 if (error != 0) {
707 goto connect_failed;
708 }
709
710 /* XXX cluster */
711
712 //DCCPS_BUMP_MIB(dccps, dccpActiveOpens);
713
714 return (0);
715
716 connect_failed:
717 cmn_err(CE_NOTE, "dccp_do_connect failed");
718
719 connp->conn_faddr_v6 = ipv6_all_zeros;
720 connp->conn_fport = 0;
721 dccp->dccp_state = oldstate;
722
723 return (error);
724 }
725
726 /*
727 * Init values of a connection.
728 */
729 void
730 dccp_init_values(dccp_t *dccp, dccp_t *parent)
731 {
732 conn_t *connp = dccp->dccp_connp;
733 dccp_stack_t *dccps = dccp->dccp_dccps;
734
735 connp->conn_mlp_type = mlptSingle;
736 }
737
738 void *
739 dccp_get_conn(void *arg, dccp_stack_t *dccps)
740 {
741 dccp_t *dccp = NULL;
742 conn_t *connp;
743 squeue_t *sqp = (squeue_t *)arg;
744 netstack_t *ns;
745
746 /* XXX timewait */
747
748 connp = ipcl_conn_create(IPCL_DCCPCONN, KM_NOSLEEP,
749 dccps->dccps_netstack);
750 if (connp == NULL) {
751 return (NULL);
752 }
753
754 dccp = connp->conn_dccp;
755 dccp->dccp_dccps = dccps;
756
757 connp->conn_recv = dccp_input_data;
758 connp->conn_recvicmp = dccp_icmp_input;
759 connp->conn_verifyicmp = dccp_verifyicmp;
760
761 connp->conn_ixa->ixa_notify = dccp_notify;
762 connp->conn_ixa->ixa_notify_cookie = dccp;
763
764 return ((void *)connp);
765 }
766
767 /*
768 * IPv4 connect.
769 */
770 static int
771 dccp_connect_ipv4(dccp_t *dccp, ipaddr_t *dstaddrp, in_port_t dstport,
772 uint_t srcid)
773 {
774 conn_t *connp = dccp->dccp_connp;
775 dccp_stack_t *dccps = dccp->dccp_dccps;
776 ipaddr_t dstaddr = *dstaddrp;
777 uint16_t lport;
778 int error;
779
780 cmn_err(CE_NOTE, "dccp.c: dccp_connect_ipv4");
781
782 ASSERT(connp->conn_ipversion == IPV4_VERSION);
783
784 if (dstaddr == INADDR_ANY) {
785 dstaddr = htonl(INADDR_LOOPBACK);
786 *dstaddrp = dstaddr;
787 }
788
789 if (srcid != 0 && connp->conn_laddr_v4 == INADDR_ANY) {
790 ip_srcid_find_id(srcid, &connp->conn_laddr_v6,
791 IPCL_ZONEID(connp), dccps->dccps_netstack);
792 connp->conn_saddr_v6 = connp->conn_laddr_v6;
793 }
794
795 IN6_IPADDR_TO_V4MAPPED(dstaddr, &connp->conn_faddr_v6);
796 connp->conn_fport = dstport;
797
798 if (dccp->dccp_state == DCCPS_CLOSED) {
799 lport = dccp_update_next_port(dccps->dccps_next_port_to_try,
800 dccp, B_TRUE);
801 lport = dccp_bindi(dccp, lport, &connp->conn_laddr_v6, 0,
802 B_TRUE, B_FALSE, B_FALSE);
803
804 if (lport == 0) {
805 return (-TNOADDR);
806 }
807 }
808
809 error = dccp_set_destination(dccp);
810 if (error != 0) {
811 return (error);
812 }
813
814 /*
815 * Don't connect to oneself.
816 */
817 if (connp->conn_faddr_v4 == connp->conn_laddr_v4 &&
818 connp->conn_fport == connp->conn_lport) {
819 return (-TBADADDR);
820 }
821
822 /* XXX state */
823
824 return (ipcl_conn_insert_v4(connp));
825 }
826
827 /*
828 * IPv6 connect.
829 */
830 static int
831 dccp_connect_ipv6(dccp_t *dccp, in6_addr_t *dstaddrp, in_port_t dstport,
832 uint32_t flowinfo, uint_t srcid, uint32_t scope_id)
833 {
834 cmn_err(CE_NOTE, "dccp.c: dccp_connect_ipv6");
835
836 return (0);
837 }
838
839 /*
840 * Set the ports via conn_connect and build the template
841 * headers.
842 */
843 int
844 dccp_set_destination(dccp_t *dccp)
845 {
846 conn_t *connp = dccp->dccp_connp;
847 dccp_stack_t *dccps = dccp->dccp_dccps;
848 iulp_t uinfo;
849 uint32_t flags;
850 int error;
851
852 flags = IPDF_LSO | IPDF_ZCOPY;
853 flags |= IPDF_UNIQUE_DCE;
854
855 mutex_enter(&connp->conn_lock);
856 error = conn_connect(connp, &uinfo, flags);
857 mutex_exit(&connp->conn_lock);
858 if (error != 0) {
859 cmn_err(CE_NOTE, "conn_connect failed");
860 return (error);
861 }
862
863 error = dccp_build_hdrs(dccp);
864 if (error != 0) {
865 cmn_err(CE_NOTE, "dccp_build_hdrs failed");
866 return (error);
867 }
868
869 /* XXX */
870
871 mutex_enter(&connp->conn_lock);
872 connp->conn_state_flags &= ~CONN_INCIPIENT;
873 mutex_exit(&connp->conn_lock);
874
875 return (0);
876 }