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 function related to the socket interface. 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/squeue_impl.h> 44 #include <sys/squeue.h> 45 #include <sys/socketvar.h> 46 47 #include <inet/common.h> 48 #include <inet/dccp_impl.h> 49 #include <inet/dccp_stack.h> 50 #include <inet/proto_set.h> 51 #include <inet/ip.h> 52 53 #include <sys/cmn_err.h> 54 55 static void dccp_activate(sock_lower_handle_t, sock_upper_handle_t, 56 sock_upcalls_t *, int, cred_t *); 57 static int dccp_accept(sock_lower_handle_t, sock_lower_handle_t, 58 sock_upper_handle_t, cred_t *); 59 static int dccp_bind(sock_lower_handle_t, struct sockaddr *, 60 socklen_t, cred_t *); 61 static int dccp_listen(sock_lower_handle_t, int, cred_t *); 62 static int dccp_connect(sock_lower_handle_t, const struct sockaddr *, 63 socklen_t, sock_connid_t *, cred_t *); 64 static int dccp_getpeername(sock_lower_handle_t, struct sockaddr *, 65 socklen_t *, cred_t *); 66 static int dccp_getsockname(sock_lower_handle_t, struct sockaddr *, 67 socklen_t *, cred_t *); 68 static int dccp_getsockopt(sock_lower_handle_t, int, int, void *, 69 socklen_t *, cred_t *); 70 static int dccp_setsockopt(sock_lower_handle_t, int, int, const void *, 71 socklen_t, cred_t *); 72 static int dccp_send(sock_lower_handle_t, mblk_t *, struct nmsghdr *, 73 cred_t *); 74 static int dccp_shutdown(sock_lower_handle_t, int, cred_t *); 75 static void dccp_clr_flowctrl(sock_lower_handle_t); 76 static int dccp_ioctl(sock_lower_handle_t, int, intptr_t, int, int32_t *, 77 cred_t *); 78 static int dccp_close(sock_lower_handle_t, int, cred_t *); 79 80 sock_downcalls_t sock_dccp_downcalls = { 81 dccp_activate, /* sd_activate */ 82 dccp_accept, /* sd_accept */ 83 dccp_bind, /* sd_bind */ 84 dccp_listen, /* sd_listen */ 85 dccp_connect, /* sd_connect */ 86 dccp_getpeername, /* sd_getpeername */ 87 dccp_getsockname, /* sd_getsockname */ 88 dccp_getsockopt, /* sd_getsockopt */ 89 dccp_setsockopt, /* sd_setsockopt */ 90 dccp_send, /* sd_send */ 91 NULL, /* sd_send_uio */ 92 NULL, /* sd_recv_uio */ 93 NULL, /* sd_poll */ 94 dccp_shutdown, /* sd_shutdown */ 95 dccp_clr_flowctrl, /* sd_setflowctrl */ 96 dccp_ioctl, /* sd_ioctl */ 97 dccp_close, /* sd_close */ 98 }; 99 100 /* ARGSUSED */ 101 static void 102 dccp_activate(sock_lower_handle_t proto_handle, sock_upper_handle_t sock_handle, 103 sock_upcalls_t *sock_upcalls, int flags, cred_t *cr) 104 { 105 conn_t *connp = (conn_t *)proto_handle; 106 struct sock_proto_props sopp; 107 extern struct module_info dccp_rinfo; 108 109 cmn_err(CE_NOTE, "dccp_socket.c: dccp_activate"); 110 111 ASSERT(connp->conn_upper_handle == NULL); 112 113 /* All Solaris components should pass a cred for this operation */ 114 ASSERT(cr != NULL); 115 116 sopp.sopp_flags = SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT | 117 SOCKOPT_MAXPSZ | SOCKOPT_MAXBLK | SOCKOPT_RCVTIMER | 118 SOCKOPT_RCVTHRESH | SOCKOPT_MAXADDRLEN | SOCKOPT_MINPSZ; 119 120 sopp.sopp_rxhiwat = SOCKET_RECVHIWATER; 121 sopp.sopp_rxlowat = SOCKET_RECVLOWATER; 122 sopp.sopp_maxpsz = INFPSZ; 123 sopp.sopp_maxblk = INFPSZ; 124 sopp.sopp_rcvtimer = SOCKET_TIMER_INTERVAL; 125 sopp.sopp_rcvthresh = SOCKET_RECVHIWATER >> 3; 126 sopp.sopp_maxaddrlen = sizeof (sin6_t); 127 sopp.sopp_minpsz = (dccp_rinfo.mi_minpsz == 1) ? 0 : 128 dccp_rinfo.mi_minpsz; 129 130 connp->conn_upcalls = sock_upcalls; 131 connp->conn_upper_handle = sock_handle; 132 133 /* XXX conn_rcvbuf */ 134 (*connp->conn_upcalls->su_set_proto_props)(connp->conn_upper_handle, 135 &sopp); 136 } 137 138 /*ARGSUSED*/ 139 static int 140 dccp_accept(sock_lower_handle_t lproto_handle, 141 sock_lower_handle_t eproto_handle, sock_upper_handle_t sock_handle, 142 cred_t *cr) 143 { 144 conn_t *lconnp, *econnp; 145 dccp_t *listener, *eager; 146 147 cmn_err(CE_NOTE, "dccp_socket.c: dccp_accept"); 148 149 econnp = (conn_t *)eproto_handle; 150 eager = econnp->conn_dccp; 151 ASSERT(IPCL_IS_NONSTR(econnp)); 152 ASSERT(eager->dccp_listener != NULL); 153 listener = eager->dccp_listener; 154 lconnp = (conn_t *)listener->dccp_connp; 155 ASSERT(listener->dccp_state == DCCPS_LISTEN); 156 ASSERT(lconnp->conn_upper_handle != NULL); 157 158 ASSERT(econnp->conn_upper_handle == NULL || 159 econnp->conn_upper_handle == sock_handle); 160 ASSERT(econnp->conn_upcalls == NULL || 161 econnp->conn_upcalls == lconnp->conn_upcalls); 162 econnp->conn_upper_handle = sock_handle; 163 econnp->conn_upcalls = lconnp->conn_upcalls; 164 165 ASSERT(econnp->conn_netstack == 166 listener->dccp_connp->conn_netstack); 167 ASSERT(eager->dccp_dccps == listener->dccp_dccps); 168 169 ASSERT(econnp->conn_ref >= 2); 170 eager->dccp_listener = NULL; /* XXX */ 171 CONN_DEC_REF(listener->dccp_connp); 172 173 return (0); 174 } 175 176 static int 177 dccp_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa, 178 socklen_t len, cred_t *cr) 179 { 180 conn_t *connp = (conn_t *)proto_handle; 181 int error; 182 183 cmn_err(CE_NOTE, "dccp_socket.c: dccp_bind"); 184 185 ASSERT(connp->conn_upper_handle != NULL); 186 187 /* All Solaris components should pass a cred for this operation */ 188 ASSERT(cr != NULL); 189 190 error = squeue_synch_enter(connp, NULL); 191 if (error != 0) { 192 /* Failed to enter */ 193 return (ENOSR); 194 } 195 196 /* Binding to NULL address means unbind */ 197 if (sa == NULL) { 198 if (connp->conn_dccp->dccp_state < DCCPS_LISTEN) { 199 error = dccp_do_unbind(connp); 200 } else { 201 error = EINVAL; 202 } 203 } else { 204 error = dccp_do_bind(connp, sa, len, cr, B_TRUE); 205 } 206 207 squeue_synch_exit(connp); 208 209 if (error < 0) { 210 if (error == -TOUTSTATE) { 211 error = EINVAL; 212 } else { 213 error = proto_tlitosyserr(-error); 214 } 215 } 216 217 return (error); 218 } 219 220 /* ARGSUSED */ 221 static int 222 dccp_listen(sock_lower_handle_t proto_handle, int backlog, cred_t *cr) 223 { 224 conn_t *connp = (conn_t *)proto_handle; 225 dccp_t *dccp = connp->conn_dccp; 226 int error; 227 228 cmn_err(CE_NOTE, "dccp_socket.c: dccp_listen"); 229 230 ASSERT(connp->conn_upper_handle != NULL); 231 232 /* All Solaris components should pass a cred for this operation */ 233 ASSERT(cr != NULL); 234 235 error = squeue_synch_enter(connp, NULL); 236 if (error != 0) { 237 /* Failed to enter */ 238 return (ENOBUFS); 239 } 240 241 error = dccp_do_listen(connp, NULL, 0, backlog, cr, B_FALSE); 242 if (error == 0) { 243 /* XXX:DCCP */ 244 (*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle, 245 SOCK_OPCTL_ENAB_ACCEPT, 246 (uintptr_t)(10)); 247 } else if (error < 0) { 248 if (error == -TOUTSTATE) { 249 error = EINVAL; 250 } else { 251 error = proto_tlitosyserr(-error); 252 } 253 } 254 255 squeue_synch_exit(connp); 256 257 return (error); 258 } 259 260 static int 261 dccp_connect(sock_lower_handle_t proto_handle, const struct sockaddr *sa, 262 socklen_t len, sock_connid_t *id, cred_t *cr) 263 { 264 conn_t *connp = (conn_t *)proto_handle; 265 int error; 266 267 cmn_err(CE_NOTE, "dccp_socket.c: dccp_connect"); 268 269 ASSERT(connp->conn_upper_handle != NULL); 270 271 /* All Solaris components should pass a cred for this operation */ 272 ASSERT(cr != NULL); 273 274 error = proto_verify_ip_addr(connp->conn_family, sa, len); 275 if (error != 0) { 276 return (error); 277 } 278 279 error = squeue_synch_enter(connp, NULL); 280 if (error != 0) { 281 /* Failed to enter */ 282 return (ENOSR); 283 } 284 285 error = dccp_do_connect(connp, sa, len, cr, curproc->p_pid); 286 if (error == 0) { 287 *id = connp->conn_dccp->dccp_connid; 288 } else if (error < 0) { 289 if (error == -TOUTSTATE) { 290 switch (connp->conn_dccp->dccp_state) { 291 case DCCPS_REQUEST: 292 error = EALREADY; 293 break; 294 case DCCPS_PARTOPEN: 295 error = EISCONN; 296 break; 297 case DCCPS_LISTEN: 298 error = EOPNOTSUPP; 299 break; 300 default: 301 error = EINVAL; 302 break; 303 } 304 } else { 305 error = proto_tlitosyserr(-error); 306 } 307 } 308 309 squeue_synch_exit(connp); 310 311 cmn_err(CE_NOTE, "dccp_connect.c: exit %d", error); 312 return ((error == 0) ? EINPROGRESS : error); 313 } 314 315 /* ARGSUSED3 */ 316 static int 317 dccp_getpeername(sock_lower_handle_t proto_handle, struct sockaddr *addr, 318 socklen_t *addrlenp, cred_t *cr) 319 { 320 conn_t *connp = (conn_t *)proto_handle; 321 dccp_t *dccp = connp->conn_dccp; 322 323 cmn_err(CE_NOTE, "dccp_socket.c: dccp_getpeername"); 324 325 /* All Solaris components should pass a cred for this operation */ 326 ASSERT(cr != NULL); 327 328 ASSERT(dccp != NULL); 329 if (dccp->dccp_state < DCCPS_OPEN) { 330 return (ENOTCONN); 331 } 332 333 return (conn_getpeername(connp, addr, addrlenp)); 334 } 335 336 /* ARGSUSED3 */ 337 static int 338 dccp_getsockname(sock_lower_handle_t proto_handle, struct sockaddr *addr, 339 socklen_t *addrlenp, cred_t *cr) 340 { 341 conn_t *connp = (conn_t *)proto_handle; 342 int error; 343 344 cmn_err(CE_NOTE, "dccp_socket.c: dccp_getsockname"); 345 346 /* All Solaris components should pass a cred for this operation */ 347 ASSERT(cr != NULL); 348 349 /* XXX UDP has locks here, TCP not */ 350 mutex_enter(&connp->conn_lock); 351 error = conn_getsockname(connp, addr, addrlenp); 352 mutex_exit(&connp->conn_lock); 353 354 return (error); 355 } 356 357 static int 358 dccp_getsockopt(sock_lower_handle_t proto_handle, int level, int option_name, 359 void *optvalp, socklen_t *optlen, cred_t *cr) 360 { 361 conn_t *connp = (conn_t *)proto_handle; 362 void *optvalp_buf; 363 t_uscalar_t max_optbuf_len; 364 int len; 365 int error; 366 367 cmn_err(CE_NOTE, "dccp_socket.c: dccp_getsockopt"); 368 369 ASSERT(connp->conn_upper_handle != NULL); 370 371 /* All Solaris components should pass a cred for this operation */ 372 ASSERT(cr != NULL); 373 374 error = proto_opt_check(level, option_name, *optlen, &max_optbuf_len, 375 dccp_opt_obj.odb_opt_des_arr, 376 dccp_opt_obj.odb_opt_arr_cnt, 377 B_FALSE, B_TRUE, cr); 378 if (error != 0) { 379 if (error < 0) { 380 error = proto_tlitosyserr(-error); 381 } 382 return (error); 383 } 384 385 optvalp_buf = kmem_alloc(max_optbuf_len, KM_SLEEP); 386 if (optvalp_buf == NULL) { 387 return (ENOMEM); 388 } 389 390 error = squeue_synch_enter(connp, NULL); 391 if (error == ENOMEM) { 392 kmem_free(optvalp_buf, max_optbuf_len); 393 return (ENOMEM); 394 } 395 396 len = dccp_opt_get(connp, level, option_name, optvalp_buf); 397 squeue_synch_exit(connp); 398 399 if (len == -1) { 400 kmem_free(optvalp_buf, max_optbuf_len); 401 return (EINVAL); 402 } 403 404 t_uscalar_t size = MIN(len, *optlen); 405 406 bcopy(optvalp_buf, optvalp, size); 407 bcopy(&size, optlen, sizeof (size)); 408 409 kmem_free(optvalp_buf, max_optbuf_len); 410 411 return (0); 412 } 413 414 static int 415 dccp_setsockopt(sock_lower_handle_t proto_handle, int level, int option_name, 416 const void *optvalp, socklen_t optlen, cred_t *cr) 417 { 418 conn_t *connp = (conn_t *)proto_handle; 419 int error; 420 421 cmn_err(CE_NOTE, "dccp_socket.c: dccp_setsockopt"); 422 423 ASSERT(connp->conn_upper_handle != NULL); 424 425 /* All Solaris components should pass a cred for this operation */ 426 ASSERT(cr != NULL); 427 428 error = squeue_synch_enter(connp, NULL); 429 if (error == ENOMEM) { 430 return (ENOMEM); 431 } 432 433 error = proto_opt_check(level, option_name, optlen, NULL, 434 dccp_opt_obj.odb_opt_des_arr, 435 dccp_opt_obj.odb_opt_arr_cnt, 436 B_TRUE, B_FALSE, cr); 437 if (error != 0) { 438 if (error < 0) { 439 error = proto_tlitosyserr(-error); 440 } 441 squeue_synch_exit(connp); 442 return (error); 443 } 444 445 error = dccp_opt_set(connp, SETFN_OPTCOM_NEGOTIATE, level, option_name, 446 optlen, (uchar_t *)optvalp, (uint_t *)&optlen, (uchar_t *)optvalp, 447 NULL, cr); 448 squeue_synch_exit(connp); 449 450 ASSERT(error >= 0); 451 452 return (error); 453 } 454 455 /* ARGSUSED */ 456 static int 457 dccp_send(sock_lower_handle_t proto_handle, mblk_t *mp, struct nmsghdr *msg, 458 cred_t *cr) 459 { 460 conn_t *connp = (conn_t *)proto_handle; 461 dccp_t *dccp; 462 uint32_t msize; 463 int32_t dccpstate; 464 465 cmn_err(CE_NOTE, "dccp_socket.c: dccp_send"); 466 467 /* All Solaris components should pass a cred for this operation */ 468 ASSERT(cr != NULL); 469 470 ASSERT(connp->conn_ref >= 2); 471 ASSERT(connp->conn_upper_handle != NULL); 472 473 if (msg->msg_controllen != 0) { 474 freemsg(mp); 475 return (EOPNOTSUPP); 476 } 477 478 switch (DB_TYPE(mp)) { 479 case M_DATA: 480 dccp = connp->conn_dccp; 481 ASSERT(dccp != NULL); 482 483 dccpstate = dccp->dccp_state; 484 if (dccpstate < DCCPS_OPEN) { 485 freemsg(mp); 486 487 return ((dccpstate == DCCPS_REQUEST) ? ENOTCONN : 488 ((dccp->dccp_connid > 0) ? EPIPE : ENOTCONN)); 489 } else if (dccpstate > DCCPS_CLOSING) { 490 freemsg(mp); 491 return (EPIPE); 492 } 493 494 /* XXX */ 495 496 msize = msgdsize(mp); 497 498 CONN_INC_REF(connp); 499 500 if (msg->msg_flags & MSG_OOB) { 501 SQUEUE_ENTER_ONE(connp->conn_sqp, mp, dccp_output_urgent, 502 connp, NULL, dccp_squeue_flag, SQTAG_DCCP_OUTPUT); 503 } else { 504 SQUEUE_ENTER_ONE(connp->conn_sqp, mp, dccp_output, 505 connp, NULL, dccp_squeue_flag, SQTAG_DCCP_OUTPUT); 506 } 507 508 return (0); 509 510 default: 511 ASSERT(0); 512 } 513 514 freemsg(mp); 515 516 return (0); 517 } 518 519 /* ARGSUSED */ 520 static int 521 dccp_shutdown(sock_lower_handle_t proto_handle, int how, cred_t *cr) 522 { 523 conn_t *connp = (conn_t *)proto_handle; 524 dccp_t *dccp = connp->conn_dccp; 525 526 cmn_err(CE_NOTE, "dccp_socket.c: dccp_shutdown"); 527 528 /* All Solaris components should pass a cred for this operation. */ 529 ASSERT(cr != NULL); 530 531 ASSERT(connp->conn_upper_handle != NULL); 532 533 534 return (ENOTSUP); 535 } 536 537 static void 538 dccp_clr_flowctrl(sock_lower_handle_t proto_handle) 539 { 540 conn_t *connp = (conn_t *)proto_handle; 541 dccp_t *dccp = connp->conn_dccp; 542 mblk_t *mp; 543 int error; 544 545 ASSERT(connp->conn_upper_handle != NULL); 546 547 cmn_err(CE_NOTE, "dccp_socket.c: dccp_clr_flowctrl"); 548 549 error = squeue_synch_enter(connp, mp); 550 551 squeue_synch_exit(connp); 552 } 553 554 /* ARGSUSED */ 555 static int 556 dccp_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg, 557 int mode, int32_t *rvalp, cred_t *cr) 558 { 559 conn_t *connp = (conn_t *)proto_handle; 560 int error; 561 562 cmn_err(CE_NOTE, "dccp_socket.c: dccp_ioctl"); 563 564 ASSERT(connp->conn_upper_handle != NULL); 565 566 /* All Solaris components should pass a cred for this operation. */ 567 ASSERT(cr != NULL); 568 569 return (ENOTSUP); 570 } 571 572 /* ARGSUSED */ 573 static int 574 dccp_close(sock_lower_handle_t proto_handle, int flags, cred_t *cr) 575 { 576 conn_t *connp = (conn_t *)proto_handle; 577 578 cmn_err(CE_NOTE, "dccp_socket.c: dccp_close\n"); 579 580 ASSERT(connp->conn_upper_handle != NULL); 581 582 /* All Solaris components should pass a cred for this operation */ 583 ASSERT(cr != NULL); 584 585 dccp_close_common(connp, flags); 586 587 ip_free_helper_stream(connp); 588 589 CONN_DEC_REF(connp); 590 591 /* 592 * EINPROGRESS tells sockfs to wait for a 'closed' upcall before 593 * freeing the socket. 594 */ 595 return (EINPROGRESS); 596 } 597 598 599 /* 600 * Socket create function. 601 */ 602 sock_lower_handle_t 603 dccp_create(int family, int type, int proto, sock_downcalls_t **sockdowncalls, 604 uint_t *smodep, int *errorp, int flags, cred_t *credp) 605 { 606 conn_t *connp; 607 boolean_t isv6; 608 609 /* XXX (type != SOCK_STREAM */ 610 if ((family != AF_INET && family != AF_INET6) || 611 (proto != 0 && proto != IPPROTO_DCCP)) { 612 *errorp = EPROTONOSUPPORT; 613 return (NULL); 614 } 615 616 cmn_err(CE_NOTE, "dccp_socket: dccp_create\n"); 617 618 isv6 = family == AF_INET6 ? B_TRUE: B_FALSE; 619 connp = dccp_create_common(credp, isv6, B_TRUE, errorp); 620 if (connp == NULL) { 621 return (NULL); 622 } 623 624 /* 625 * Increment ref for DCCP connection. 626 */ 627 mutex_enter(&connp->conn_lock); 628 CONN_INC_REF_LOCKED(connp); 629 ASSERT(connp->conn_ref == 2); 630 connp->conn_state_flags &= ~CONN_INCIPIENT; 631 connp->conn_flags |= IPCL_NONSTR; 632 mutex_exit(&connp->conn_lock); 633 634 ASSERT(errorp != NULL); 635 *errorp = 0; 636 *sockdowncalls = &sock_dccp_downcalls; 637 *smodep = SM_CONNREQUIRED | SM_EXDATA | SM_ACCEPTSUPP | 638 SM_SENDFILESUPP; 639 640 return ((sock_lower_handle_t)connp); 641 } 642 643 int 644 dccp_fallback(sock_lower_handle_t proto_handle, queue_t *q, 645 boolean_t issocket, so_proto_quiesced_cb_t quiesced_cb, 646 sock_quiesce_arg_t *arg) 647 { 648 cmn_err(CE_NOTE, "dccp_socket: dccp_fallback\n"); 649 650 return (0); 651 } 652 653 /* 654 * Notifies a non-STREAMS based listener about a new connection. This 655 * function is executed on the *eager*'s squeue once the 3 way handshake 656 * has completed. Note that the behavior differs from STREAMS, where the 657 * T_CONN_IND is sent up by tcp_send_conn_ind() while on the *listener*'s 658 * squeue. 659 * 660 * Returns B_TRUE if the notification succeeded and an upper handle was 661 * obtained. `tcp' should be closed on failure. 662 */ 663 boolean_t 664 dccp_newconn_notify(dccp_t *dccp, ip_recv_attr_t *ira) 665 { 666 dccp_t *listener = dccp->dccp_listener; 667 dccp_t *tail; 668 conn_t *lconnp = listener->dccp_connp; 669 conn_t *econnp = dccp->dccp_connp; 670 ipaddr_t *addr_cache; 671 sock_upper_handle_t upper; 672 struct sock_proto_props sopp; 673 674 cmn_err(CE_NOTE, "dccp_socket.c: dccp_newconn_notify"); 675 676 if (lconnp->conn_upcalls) { 677 cmn_err(CE_NOTE, "NOT NULL"); 678 } else { 679 cmn_err(CE_NOTE, "ISSSSSS NULL"); 680 } 681 682 if ((upper = (*lconnp->conn_upcalls->su_newconn) 683 (lconnp->conn_upper_handle, (sock_lower_handle_t)econnp, 684 &sock_dccp_downcalls, ira->ira_cred, ira->ira_cpid, 685 &econnp->conn_upcalls)) == NULL) { 686 return (B_FALSE); 687 } 688 econnp->conn_upper_handle = upper; 689 690 (*econnp->conn_upcalls->su_set_proto_props) 691 (econnp->conn_upper_handle, &sopp); 692 693 return (B_TRUE); 694 }