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