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