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 }