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 contains all DCCP kernel socket related functions.
  33  */
  34 
  35 #include <sys/types.h>
  36 #include <sys/strlog.h>
  37 #include <sys/policy.h>
  38 #include <sys/sockio.h>
  39 #include <sys/strsubr.h>
  40 #include <sys/strsun.h>
  41 #define _SUN_TPI_VERSION 2
  42 #include <sys/tihdr.h>
  43 #include <sys/timod.h>
  44 #include <sys/squeue_impl.h>
  45 #include <sys/squeue.h>
  46 #include <sys/socketvar.h>
  47 
  48 #include <inet/common.h>
  49 #include <inet/dccp_impl.h>
  50 #include <inet/dccp_stack.h>
  51 #include <inet/proto_set.h>
  52 #include <inet/ip.h>
  53 
  54 #include <sys/cmn_err.h>
  55 
  56 static void     dccp_activate(sock_lower_handle_t, sock_upper_handle_t,
  57                     sock_upcalls_t *, int, cred_t *);
  58 static int      dccp_accept(sock_lower_handle_t, sock_lower_handle_t,
  59                     sock_upper_handle_t, cred_t *);
  60 static int      dccp_bind(sock_lower_handle_t, struct sockaddr *,
  61                     socklen_t, cred_t *);
  62 static int      dccp_listen(sock_lower_handle_t, int, cred_t *);
  63 static int      dccp_connect(sock_lower_handle_t, const struct sockaddr *,
  64                     socklen_t, sock_connid_t *, cred_t *);
  65 static int      dccp_getpeername(sock_lower_handle_t, struct sockaddr *,
  66                     socklen_t *, cred_t *);
  67 static int      dccp_getsockname(sock_lower_handle_t, struct sockaddr *,
  68                     socklen_t *, cred_t *);
  69 static int      dccp_getsockopt(sock_lower_handle_t, int, int, void *,
  70                     socklen_t *, cred_t *);
  71 static int      dccp_setsockopt(sock_lower_handle_t, int, int, const void *,
  72                     socklen_t, cred_t *);
  73 static int      dccp_send(sock_lower_handle_t, mblk_t *, struct nmsghdr *,
  74                     cred_t *);
  75 static int      dccp_shutdown(sock_lower_handle_t, int, cred_t *);
  76 static void     dccp_clr_flowctrl(sock_lower_handle_t);
  77 static int      dccp_ioctl(sock_lower_handle_t, int, intptr_t, int, int32_t *,
  78                     cred_t *);
  79 static int      dccp_close(sock_lower_handle_t, int, cred_t *);
  80 
  81 sock_downcalls_t sock_dccp_downcalls = {
  82         dccp_activate,          /* sd_activate */
  83         dccp_accept,            /* sd_accept */
  84         dccp_bind,              /* sd_bind */
  85         dccp_listen,            /* sd_listen */
  86         dccp_connect,           /* sd_connect */
  87         dccp_getpeername,       /* sd_getpeername */
  88         dccp_getsockname,       /* sd_getsockname */
  89         dccp_getsockopt,        /* sd_getsockopt */
  90         dccp_setsockopt,        /* sd_setsockopt */
  91         dccp_send,              /* sd_send */
  92         NULL,                   /* sd_send_uio */
  93         NULL,                   /* sd_recv_uio */
  94         NULL,                   /* sd_poll */
  95         dccp_shutdown,          /* sd_shutdown */
  96         dccp_clr_flowctrl,      /* sd_setflowctrl */
  97         dccp_ioctl,             /* sd_ioctl */
  98         dccp_close,             /* sd_close */
  99 };
 100 
 101 /* ARGSUSED */
 102 static void
 103 dccp_activate(sock_lower_handle_t proto_handle, sock_upper_handle_t sock_handle,
 104     sock_upcalls_t *sock_upcalls, int flags, cred_t *cr)
 105 {
 106         conn_t *connp = (conn_t *)proto_handle;
 107         struct sock_proto_props         sopp;
 108         extern struct module_info       dccp_rinfo;
 109 
 110         cmn_err(CE_NOTE, "dccp_socket.c: dccp_activate");
 111 
 112         ASSERT(connp->conn_upper_handle == NULL);
 113 
 114         /* All Solaris components should pass a cred for this operation */
 115         ASSERT(cr != NULL);
 116 
 117         sopp.sopp_flags = SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT |
 118             SOCKOPT_MAXPSZ | SOCKOPT_MAXBLK | SOCKOPT_RCVTIMER |
 119             SOCKOPT_RCVTHRESH | SOCKOPT_MAXADDRLEN | SOCKOPT_MINPSZ;
 120 
 121         sopp.sopp_rxhiwat = SOCKET_RECVHIWATER;
 122         sopp.sopp_rxlowat = SOCKET_RECVLOWATER;
 123         sopp.sopp_maxpsz = INFPSZ;
 124         sopp.sopp_maxblk = INFPSZ;
 125         sopp.sopp_rcvtimer = SOCKET_TIMER_INTERVAL;
 126         sopp.sopp_rcvthresh = SOCKET_RECVHIWATER >> 3;
 127         sopp.sopp_maxaddrlen = sizeof (sin6_t);
 128         sopp.sopp_minpsz = (dccp_rinfo.mi_minpsz == 1) ? 0 :
 129             dccp_rinfo.mi_minpsz;
 130 
 131         connp->conn_upcalls = sock_upcalls;
 132         connp->conn_upper_handle = sock_handle;
 133 
 134         /* XXX  conn_rcvbuf */
 135         (*connp->conn_upcalls->su_set_proto_props)(connp->conn_upper_handle,
 136             &sopp);
 137 }
 138 
 139 /*ARGSUSED*/
 140 static int
 141 dccp_accept(sock_lower_handle_t lproto_handle,
 142     sock_lower_handle_t eproto_handle, sock_upper_handle_t sock_handle,
 143     cred_t *cr)
 144 {
 145         conn_t  *lconnp, *econnp;
 146         dccp_t  *listener, *eager;
 147 
 148         cmn_err(CE_NOTE, "dccp_socket.c: dccp_accept");
 149 
 150         econnp = (conn_t *)eproto_handle;
 151         eager = econnp->conn_dccp;
 152         ASSERT(IPCL_IS_NONSTR(econnp));
 153         ASSERT(eager->dccp_listener != NULL);
 154         listener = eager->dccp_listener;
 155         lconnp = (conn_t *)listener->dccp_connp;
 156         ASSERT(listener->dccp_state == DCCPS_LISTEN);
 157         ASSERT(lconnp->conn_upper_handle != NULL);
 158 
 159         ASSERT(econnp->conn_upper_handle == NULL ||
 160             econnp->conn_upper_handle == sock_handle);
 161         ASSERT(econnp->conn_upcalls == NULL ||
 162             econnp->conn_upcalls == lconnp->conn_upcalls);
 163         econnp->conn_upper_handle = sock_handle;
 164         econnp->conn_upcalls = lconnp->conn_upcalls;
 165 
 166         ASSERT(econnp->conn_netstack ==
 167             listener->dccp_connp->conn_netstack);
 168         ASSERT(eager->dccp_dccps == listener->dccp_dccps);
 169 
 170         ASSERT(econnp->conn_ref >= 2);
 171         eager->dccp_listener = NULL; /* XXX */
 172         CONN_DEC_REF(listener->dccp_connp);
 173 
 174         return ((eager->dccp_state < DCCPS_OPEN) ? ECONNABORTED : 0);
 175 }
 176 
 177 static int
 178 dccp_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa,
 179     socklen_t len, cred_t *cr)
 180 {
 181         conn_t  *connp = (conn_t *)proto_handle;
 182         int     error;
 183 
 184         cmn_err(CE_NOTE, "dccp_socket.c: dccp_bind");
 185 
 186         ASSERT(connp->conn_upper_handle != NULL);
 187 
 188         /* All Solaris components should pass a cred for this operation */
 189         ASSERT(cr != NULL);
 190 
 191         error = squeue_synch_enter(connp, NULL);
 192         if (error != 0) {
 193                 /* Failed to enter */
 194                 return (ENOSR);
 195         }
 196 
 197         /* Binding to NULL address means unbind */
 198         if (sa == NULL) {
 199                 if (connp->conn_dccp->dccp_state < DCCPS_LISTEN) {
 200                         error = dccp_do_unbind(connp);
 201                 } else {
 202                         error = EINVAL;
 203                 }
 204         } else {
 205                 error = dccp_do_bind(connp, sa, len, cr, B_TRUE);
 206         }
 207 
 208         squeue_synch_exit(connp);
 209 
 210         if (error < 0) {
 211                 if (error == -TOUTSTATE) {
 212                         error = EINVAL;
 213                 } else {
 214                         error = proto_tlitosyserr(-error);
 215                 }
 216         }
 217 
 218         return (error);
 219 }
 220 
 221 /* ARGSUSED */
 222 static int
 223 dccp_listen(sock_lower_handle_t proto_handle, int backlog, cred_t *cr)
 224 {
 225         conn_t  *connp = (conn_t *)proto_handle;
 226         dccp_t  *dccp = connp->conn_dccp;
 227         int     error;
 228 
 229         cmn_err(CE_NOTE, "dccp_socket.c: dccp_listen");
 230 
 231         ASSERT(connp->conn_upper_handle != NULL);
 232 
 233         /* All Solaris components should pass a cred for this operation */
 234         ASSERT(cr != NULL);
 235 
 236         error = squeue_synch_enter(connp, NULL);
 237         if (error != 0) {
 238                 /* Failed to enter */
 239                 return (ENOBUFS);
 240         }
 241 
 242         error = dccp_do_listen(connp, NULL, 0, backlog, cr, B_FALSE);
 243         if (error == 0) {
 244                 /* XXX dccps->dccps_conn_req_max_q0 */
 245                 (*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle,
 246                     SOCK_OPCTL_ENAB_ACCEPT,
 247                     (uintptr_t)(dccp->dccp_conn_req_max));
 248         } else if (error < 0) {
 249                 if (error == -TOUTSTATE) {
 250                         error = EINVAL;
 251                 } else {
 252                         error = proto_tlitosyserr(-error);
 253                 }
 254         }
 255 
 256         squeue_synch_exit(connp);
 257 
 258         return (error);
 259 }
 260 
 261 /*
 262  * Socket connect.
 263  */
 264 static int
 265 dccp_connect(sock_lower_handle_t proto_handle, const struct sockaddr *sa,
 266     socklen_t len, sock_connid_t *id, cred_t *cr)
 267 {
 268         conn_t  *connp = (conn_t *)proto_handle;
 269         int     error;
 270 
 271         cmn_err(CE_NOTE, "dccp_socket.c: dccp_connect");
 272 
 273         ASSERT(connp->conn_upper_handle != NULL);
 274 
 275         /* All Solaris components should pass a cred for this operation */
 276         ASSERT(cr != NULL);
 277 
 278         error = proto_verify_ip_addr(connp->conn_family, sa, len);
 279         if (error != 0) {
 280                 return (error);
 281         }
 282 
 283         error = squeue_synch_enter(connp, NULL);
 284         if (error != 0) {
 285                 /* Failed to enter */
 286                 return (ENOSR);
 287         }
 288 
 289         /*
 290          * DCCP supports quick connect, so no need to do an implicit bind.
 291          */
 292         error = dccp_do_connect(connp, sa, len, cr, curproc->p_pid);
 293         if (error == 0) {
 294                 *id = connp->conn_dccp->dccp_connid;
 295         } else if (error < 0) {
 296                 if (error == -TOUTSTATE) {
 297                         switch (connp->conn_dccp->dccp_state) {
 298                         case DCCPS_REQUEST:
 299                                 error = EALREADY;
 300                                 break;
 301                         case DCCPS_PARTOPEN:
 302                                 error = EISCONN;
 303                                 break;
 304                         case DCCPS_LISTEN:
 305                                 error = EOPNOTSUPP;
 306                                 break;
 307                         default:
 308                                 error = EINVAL;
 309                                 break;
 310                         }
 311                 } else {
 312                         error = proto_tlitosyserr(-error);
 313                 }
 314         }
 315 
 316         /* XXX loopback */
 317 
 318         squeue_synch_exit(connp);
 319 
 320         return ((error == 0) ? EINPROGRESS : error);
 321 }
 322 
 323 /* ARGSUSED3 */
 324 static int
 325 dccp_getpeername(sock_lower_handle_t proto_handle, struct sockaddr *addr,
 326     socklen_t *addrlenp, cred_t *cr)
 327 {
 328         conn_t  *connp = (conn_t *)proto_handle;
 329         dccp_t  *dccp = connp->conn_dccp;
 330 
 331         cmn_err(CE_NOTE, "dccp_socket.c: dccp_getpeername");
 332 
 333         /* All Solaris components should pass a cred for this operation */
 334         ASSERT(cr != NULL);
 335 
 336         ASSERT(dccp != NULL);
 337         if (dccp->dccp_state < DCCPS_OPEN) {
 338                 return (ENOTCONN);
 339         }
 340 
 341         return (conn_getpeername(connp, addr, addrlenp));
 342 }
 343 
 344 /* ARGSUSED3 */
 345 static int
 346 dccp_getsockname(sock_lower_handle_t proto_handle, struct sockaddr *addr,
 347     socklen_t *addrlenp, cred_t *cr)
 348 {
 349         conn_t  *connp = (conn_t *)proto_handle;
 350         int     error;
 351 
 352         cmn_err(CE_NOTE, "dccp_socket.c: dccp_getsockname");
 353 
 354         /* All Solaris components should pass a cred for this operation */
 355         ASSERT(cr != NULL);
 356 
 357         /* XXX UDP has locks here, TCP not */
 358         mutex_enter(&connp->conn_lock);
 359         error = conn_getsockname(connp, addr, addrlenp);
 360         mutex_exit(&connp->conn_lock);
 361 
 362         return (error);
 363 }
 364 
 365 static int
 366 dccp_getsockopt(sock_lower_handle_t proto_handle, int level, int option_name,
 367     void *optvalp, socklen_t *optlen, cred_t *cr)
 368 {
 369         conn_t          *connp = (conn_t *)proto_handle;
 370         void            *optvalp_buf;
 371         t_uscalar_t     max_optbuf_len;
 372         int             len;
 373         int             error;
 374 
 375         cmn_err(CE_NOTE, "dccp_socket.c: dccp_getsockopt");
 376 
 377         ASSERT(connp->conn_upper_handle != NULL);
 378 
 379         /* All Solaris components should pass a cred for this operation */
 380         ASSERT(cr != NULL);
 381 
 382         error = proto_opt_check(level, option_name, *optlen, &max_optbuf_len,
 383             dccp_opt_obj.odb_opt_des_arr,
 384             dccp_opt_obj.odb_opt_arr_cnt,
 385             B_FALSE, B_TRUE, cr);
 386         if (error != 0) {
 387                 if (error < 0) {
 388                         error = proto_tlitosyserr(-error);
 389                 }
 390                 return (error);
 391         }
 392 
 393         optvalp_buf = kmem_alloc(max_optbuf_len, KM_SLEEP);
 394         if (optvalp_buf == NULL) {
 395                 return (ENOMEM);
 396         }
 397 
 398         error = squeue_synch_enter(connp, NULL);
 399         if (error == ENOMEM) {
 400                 kmem_free(optvalp_buf, max_optbuf_len);
 401                 return (ENOMEM);
 402         }
 403 
 404         len = dccp_opt_get(connp, level, option_name, optvalp_buf);
 405         squeue_synch_exit(connp);
 406 
 407         if (len == -1) {
 408                 kmem_free(optvalp_buf, max_optbuf_len);
 409                 return (EINVAL);
 410         }
 411 
 412         /*
 413          * Update optlen and copy option value.
 414          */
 415         t_uscalar_t size = MIN(len, *optlen);
 416 
 417         bcopy(optvalp_buf, optvalp, size);
 418         bcopy(&size, optlen, sizeof (size));
 419 
 420         kmem_free(optvalp_buf, max_optbuf_len);
 421 
 422         return (0);
 423 }
 424 
 425 static int
 426 dccp_setsockopt(sock_lower_handle_t proto_handle, int level, int option_name,
 427     const void *optvalp, socklen_t optlen, cred_t *cr)
 428 {
 429         conn_t  *connp = (conn_t *)proto_handle;
 430         int     error;
 431 
 432         cmn_err(CE_NOTE, "dccp_socket.c: dccp_setsockopt");
 433 
 434         ASSERT(connp->conn_upper_handle != NULL);
 435 
 436         /* All Solaris components should pass a cred for this operation */
 437         ASSERT(cr != NULL);
 438 
 439         error = squeue_synch_enter(connp, NULL);
 440         if (error == ENOMEM) {
 441                 return (ENOMEM);
 442         }
 443 
 444         error = proto_opt_check(level, option_name, optlen, NULL,
 445             dccp_opt_obj.odb_opt_des_arr,
 446             dccp_opt_obj.odb_opt_arr_cnt,
 447             B_TRUE, B_FALSE, cr);
 448 
 449         if (error != 0) {
 450                 if (error < 0) {
 451                         error = proto_tlitosyserr(-error);
 452                 }
 453                 squeue_synch_exit(connp);
 454                 return (error);
 455         }
 456 
 457         error = dccp_opt_set(connp, SETFN_OPTCOM_NEGOTIATE, level, option_name,
 458             optlen, (uchar_t *)optvalp, (uint_t *)&optlen, (uchar_t *)optvalp,
 459             NULL, cr);
 460         squeue_synch_exit(connp);
 461 
 462         ASSERT(error >= 0);
 463 
 464         return (error);
 465 }
 466 
 467 /* ARGSUSED */
 468 static int
 469 dccp_send(sock_lower_handle_t proto_handle, mblk_t *mp, struct nmsghdr *msg,
 470     cred_t *cr)
 471 {
 472         conn_t  *connp = (conn_t *)proto_handle;
 473         dccp_t  *dccp;
 474         uint32_t msize;
 475         int32_t dccpstate;
 476 
 477         cmn_err(CE_NOTE, "dccp_socket.c: dccp_send");
 478 
 479         /* All Solaris components should pass a cred for this operation */
 480         ASSERT(cr != NULL);
 481 
 482         ASSERT(connp->conn_ref >= 2);
 483         ASSERT(connp->conn_upper_handle != NULL);
 484 
 485         if (msg->msg_controllen != 0) {
 486                 freemsg(mp);
 487                 return (EOPNOTSUPP);
 488         }
 489 
 490         switch (DB_TYPE(mp)) {
 491         case M_DATA:
 492                 dccp = connp->conn_dccp;
 493                 ASSERT(dccp != NULL);
 494 
 495                 dccpstate = dccp->dccp_state;
 496                 if (dccpstate < DCCPS_OPEN) {
 497                         freemsg(mp);
 498 
 499                         /*
 500                          * We return ENOTCONN if the endpoint is trying to
 501                          * connect or has never been connected, and EPIPE if it
 502                          * has been disconnected. The connection id helps us
 503                          * distinguish between the last two cases.
 504                          */
 505                         return ((dccpstate == DCCPS_REQUEST) ? ENOTCONN :
 506                             ((dccp->dccp_connid > 0) ? EPIPE : ENOTCONN));
 507                 } else if (dccpstate > DCCPS_CLOSING) {
 508                         freemsg(mp);
 509                         return (EPIPE);
 510                 }
 511 
 512                 /* XXX */
 513 
 514                 msize = msgdsize(mp);
 515 
 516                 CONN_INC_REF(connp);
 517 
 518                 if (msg->msg_flags & MSG_OOB) {
 519                         SQUEUE_ENTER_ONE(connp->conn_sqp, mp, dccp_output_urgent,
 520                             connp, NULL, dccp_squeue_flag, SQTAG_DCCP_OUTPUT); 
 521                 } else {
 522                         SQUEUE_ENTER_ONE(connp->conn_sqp, mp, dccp_output,
 523                             connp, NULL, dccp_squeue_flag, SQTAG_DCCP_OUTPUT);
 524                 }
 525 
 526                 return (0);
 527 
 528         default:
 529                 ASSERT(0);
 530         }
 531 
 532         freemsg(mp);
 533 
 534         return (0);
 535 }
 536 
 537 /* ARGSUSED */
 538 static int
 539 dccp_shutdown(sock_lower_handle_t proto_handle, int how, cred_t *cr)
 540 {
 541         conn_t  *connp = (conn_t *)proto_handle;
 542         dccp_t  *dccp = connp->conn_dccp;
 543 
 544         cmn_err(CE_NOTE, "dccp_socket.c: dccp_shutdown");
 545 
 546         /* All Solaris components should pass a cred for this operation. */
 547         ASSERT(cr != NULL);
 548 
 549         ASSERT(connp->conn_upper_handle != NULL);
 550 
 551         /*
 552          * X/Open requires that we check the connected state.
 553          */
 554         if (dccp->dccp_state < DCCPS_REQUEST)
 555                 return (ENOTCONN);
 556 
 557         /* Shutdown the send side */
 558         if (how != SHUT_RD) {
 559                 mblk_t  *bp;
 560 
 561                 bp = allocb_wait(0, BPRI_HI, STR_NOSIG, NULL);
 562                 CONN_INC_REF(connp);
 563                 SQUEUE_ENTER_ONE(connp->conn_sqp, bp, dccp_shutdown_output,
 564                     connp, NULL, SQ_NODRAIN, SQTAG_DCCP_SHUTDOWN_OUTPUT);
 565 
 566                 (*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle,
 567                     SOCK_OPCTL_SHUT_SEND, 0);
 568         }
 569 
 570         /* Shutdown the recv side */
 571         if (how != SHUT_WR) {
 572                 (*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle,
 573                     SOCK_OPCTL_SHUT_RECV, 0);
 574         }
 575 
 576         return (0);
 577 }
 578 
 579 static void
 580 dccp_clr_flowctrl(sock_lower_handle_t proto_handle)
 581 {
 582         conn_t  *connp = (conn_t *)proto_handle;
 583         dccp_t  *dccp = connp->conn_dccp;
 584         mblk_t  *mp;
 585         int     error;
 586 
 587         ASSERT(connp->conn_upper_handle != NULL);
 588 
 589         cmn_err(CE_NOTE, "dccp_socket.c: dccp_clr_flowctrl");
 590 
 591         error = squeue_synch_enter(connp, mp);
 592         ASSERT(error == 0);
 593 
 594         squeue_synch_exit(connp);
 595 }
 596 
 597 /* ARGSUSED */
 598 static int
 599 dccp_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg,
 600     int mode, int32_t *rvalp, cred_t *cr)
 601 {
 602         conn_t  *connp = (conn_t *)proto_handle;
 603         int     error;
 604 
 605         cmn_err(CE_NOTE, "dccp_socket.c: dccp_ioctl");
 606 
 607         ASSERT(connp->conn_upper_handle != NULL);
 608 
 609         /* All Solaris components should pass a cred for this operation. */
 610         ASSERT(cr != NULL);
 611 
 612         /*
 613          * If we don't have a helper stream then create one.
 614          * ip_create_helper_stream takes care of locking the conn_t,
 615          * so this check for NULL is just a performance optimization.
 616          */
 617         if (connp->conn_helper_info == NULL) {
 618                 dccp_stack_t    *dccps = connp->conn_dccp->dccp_dccps;
 619 
 620                 /*
 621                  * Create a helper stream for non-STREAMS socket.
 622                  */
 623                 error = ip_create_helper_stream(connp, dccps->dccps_ldi_ident);
 624                 if (error != 0) {
 625                         ip0dbg(("dccp_ioctl: create of IP helper stream "
 626                             "failed %d\n", error));
 627                         return (error);
 628                 }
 629         }
 630 
 631         switch (cmd) {
 632         case ND_SET:
 633         case ND_GET:
 634         case _SIOCSOCKFALLBACK:
 635         /* XXX  case DCCP_IOC_ABORT_CONN: */
 636         case TI_GETPEERNAME:
 637         case TI_GETMYNAME:
 638                 ip1dbg(("dccp_ioctl: cmd 0x%x on non streams socket", cmd));
 639                 error = EINVAL;
 640                 break;
 641         default:
 642                 /*
 643                  * If the conn is not closing, pass on to IP using
 644                  * helper stream. Bump the ioctlref to prevent dccp_close
 645                  * from closing the rq/wq out from underneath the ioctl
 646                  * if it ends up queued or aborted/interrupted.
 647                  */
 648                 mutex_enter(&connp->conn_lock);
 649                 if (connp->conn_state_flags & (CONN_CLOSING)) {
 650                         mutex_exit(&connp->conn_lock);
 651                         error = EINVAL;
 652                         break;
 653                 }
 654                 CONN_INC_IOCTLREF_LOCKED(connp);
 655                 error = ldi_ioctl(connp->conn_helper_info->iphs_handle,
 656                     cmd, arg, mode, cr, rvalp);
 657                 CONN_DEC_IOCTLREF(connp);
 658                 break;
 659         }
 660 
 661         return (error);
 662 }
 663 
 664 /* ARGSUSED */
 665 static int
 666 dccp_close(sock_lower_handle_t proto_handle, int flags, cred_t *cr)
 667 {
 668         conn_t  *connp = (conn_t *)proto_handle;
 669 
 670         cmn_err(CE_NOTE, "dccp_socket.c: dccp_close\n");
 671 
 672         ASSERT(connp->conn_upper_handle != NULL);
 673 
 674         /* All Solaris components should pass a cred for this operation */
 675         ASSERT(cr != NULL);
 676 
 677         dccp_close_common(connp, flags);
 678 
 679         ip_free_helper_stream(connp);
 680 
 681         CONN_DEC_REF(connp);
 682 
 683         /*
 684          * EINPROGRESS tells sockfs to wait for a 'closed' upcall before
 685          * freeing the socket.
 686          */
 687         return (EINPROGRESS);
 688 }
 689 
 690 
 691 /*
 692  * Socket create function.
 693  */
 694 sock_lower_handle_t
 695 dccp_create(int family, int type, int proto, sock_downcalls_t **sockdowncalls,
 696     uint_t *smodep, int *errorp, int flags, cred_t *credp)
 697 {
 698         conn_t          *connp;
 699         boolean_t       isv6;
 700 
 701         /* XXX (type != SOCK_STREAM */
 702         if ((family != AF_INET && family != AF_INET6) ||
 703             (proto != 0 && proto != IPPROTO_DCCP)) {
 704                 *errorp = EPROTONOSUPPORT;
 705                 return (NULL);
 706         }
 707 
 708         cmn_err(CE_NOTE, "dccp_socket: dccp_create\n");
 709 
 710         isv6 = family == AF_INET6 ? B_TRUE: B_FALSE;
 711         connp = dccp_create_common(credp, isv6, B_TRUE, errorp);
 712         if (connp == NULL) {
 713                 return (NULL);
 714         }
 715 
 716         /*
 717          * Increment ref for DCCP connection.
 718          */
 719         mutex_enter(&connp->conn_lock);
 720         CONN_INC_REF_LOCKED(connp);
 721         ASSERT(connp->conn_ref == 2);
 722         connp->conn_state_flags &= ~CONN_INCIPIENT;
 723         connp->conn_flags |= IPCL_NONSTR;
 724         mutex_exit(&connp->conn_lock);
 725 
 726         ASSERT(errorp != NULL);
 727         *errorp = 0;
 728         *sockdowncalls = &sock_dccp_downcalls;
 729         *smodep = SM_CONNREQUIRED | SM_EXDATA | SM_ACCEPTSUPP |
 730             SM_SENDFILESUPP;
 731 
 732         return ((sock_lower_handle_t)connp);
 733 }
 734 
 735 int
 736 dccp_fallback(sock_lower_handle_t proto_handle, queue_t *q,
 737     boolean_t issocket, so_proto_quiesced_cb_t quiesced_cb,
 738     sock_quiesce_arg_t *arg)
 739 {
 740         cmn_err(CE_NOTE, "dccp_socket: dccp_fallback\n");
 741 
 742         return (0);
 743 }
 744 
 745 /*
 746  * Notifies a non-STREAMS based listener about a new connection. This
 747  * function is executed on the *eager*'s squeue once the 3 way handshake
 748  * has completed. Note that the behavior differs from STREAMS, where the
 749  * T_CONN_IND is sent up by tcp_send_conn_ind() while on the *listener*'s
 750  * squeue.
 751  *
 752  * Returns B_TRUE if the notification succeeded and an upper handle was
 753  * obtained. `tcp' should be closed on failure.
 754  */
 755 boolean_t
 756 dccp_newconn_notify(dccp_t *dccp, ip_recv_attr_t *ira)
 757 {
 758         dccp_t                  *listener = dccp->dccp_listener;
 759         dccp_t                  *tail;
 760         conn_t                  *lconnp = listener->dccp_connp;
 761         conn_t                  *econnp = dccp->dccp_connp;
 762         ipaddr_t                *addr_cache;
 763         sock_upper_handle_t     upper;
 764         struct sock_proto_props sopp;
 765 
 766         cmn_err(CE_NOTE, "dccp_socket.c: dccp_newconn_notify");
 767 
 768 /*
 769         mutex_enter(&listener->dccp_eager_lock);
 770         addr_cache = (ipaddr_t *)(listener->dccp_ip_addr_cache);
 771         if (addr_cache != NULL) {
 772                 addr_cache[IP_ADDR_CACHE_HASH(dccp->dccp_connp->conn_faddr_v4)] =
 773                     dccp->dccp_connp->conn_faddr_v4;
 774         }
 775         mutex_exit(&listener->dccp_eager_lock);
 776 */
 777 
 778         /*
 779          * Notify the ULP about the new connection.
 780          */
 781         if ((upper = (*lconnp->conn_upcalls->su_newconn)
 782                 (lconnp->conn_upper_handle, (sock_lower_handle_t)econnp,
 783                 &sock_dccp_downcalls, ira->ira_cred, ira->ira_cpid,
 784                 &econnp->conn_upcalls)) == NULL) {
 785                         return (B_FALSE);
 786         }
 787         econnp->conn_upper_handle = upper;
 788 
 789         dccp->dccp_detached = B_FALSE;
 790         dccp->dccp_hard_binding = B_FALSE;
 791         dccp->dccp_tconnind_started = B_TRUE;
 792 
 793         if (econnp->conn_keepalive) {
 794                 dccp->dccp_ka_last_intrvl = 0;
 795                 dccp->dccp_ka_tid = DCCP_TIMER(dccp, dccp_keepalive_timer,
 796                     dccp->dccp_ka_interval);
 797         }
 798 
 799         /* Update the necessary parameters */
 800         dccp_get_proto_props(dccp, &sopp);
 801 
 802         (*econnp->conn_upcalls->su_set_proto_props)
 803             (econnp->conn_upper_handle, &sopp);
 804 
 805         return (B_TRUE);
 806 }