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 }