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 }