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/proto_set.h> 49 #include <inet/ip.h> 50 51 #include <sys/cmn_err.h> 52 53 #include "dccp_impl.h" 54 #include "dccp_stack.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 /* 129 sopp.sopp_minpsz = (dccp_rinfo.mi_minpsz == 1) ? 0 : 130 dccp_rinfo.mi_minpsz; 131 */ 132 connp->conn_upcalls = sock_upcalls; 133 connp->conn_upper_handle = sock_handle; 134 135 /* XXX */ 136 (*connp->conn_upcalls->su_set_proto_props)(connp->conn_upper_handle, 137 &sopp); 138 } 139 140 /*ARGSUSED*/ 141 static int 142 dccp_accept(sock_lower_handle_t lproto_handle, 143 sock_lower_handle_t eproto_handle, sock_upper_handle_t sock_handle, 144 cred_t *cr) 145 { 146 conn_t *lconnp, *econnp; 147 dccp_t *listener, *eager; 148 149 cmn_err(CE_NOTE, "dccp_socket.c: dccp_accept"); 150 151 econnp = (conn_t *)eproto_handle; 152 eager = econnp->conn_dccp; 153 154 ASSERT(IPCL_IS_NONSTR(econnp)); 155 156 ASSERT(econnp->conn_upper_handle == NULL || 157 econnp->conn_upper_handle == sock_handle); 158 159 return (ENOTSUP); 160 } 161 162 static int 163 dccp_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa, 164 socklen_t len, cred_t *cr) 165 { 166 conn_t *connp = (conn_t *)proto_handle; 167 int error; 168 169 cmn_err(CE_NOTE, "dccp_socket.c: dccp_bind"); 170 171 ASSERT(connp->conn_upper_handle != NULL); 172 173 /* All Solaris components should pass a cred for this operation */ 174 ASSERT(cr != NULL); 175 176 error = squeue_synch_enter(connp, NULL); 177 if (error != 0) { 178 /* Failed to enter */ 179 return (ENOSR); 180 } 181 182 /* Binding to NULL address means unbind */ 183 if (sa == NULL) { 184 if (connp->conn_dccp->dccp_state < DCCPS_LISTEN) { 185 error = dccp_do_unbind(connp); 186 } else { 187 error = EINVAL; 188 } 189 } else { 190 error = dccp_do_bind(connp, sa, len, cr, B_TRUE); 191 } 192 193 squeue_synch_exit(connp); 194 195 if (error < 0) { 196 if (error == -TOUTSTATE) { 197 error = EINVAL; 198 } else { 199 error = proto_tlitosyserr(-error); 200 } 201 } 202 203 return (error); 204 } 205 206 /* ARGSUSED */ 207 static int 208 dccp_listen(sock_lower_handle_t proto_handle, int backlog, cred_t *cr) 209 { 210 conn_t *connp = (conn_t *)proto_handle; 211 dccp_t *dccp = connp->conn_dccp; 212 int error; 213 214 cmn_err(CE_NOTE, "dccp_socket.c: dccp_listen"); 215 216 ASSERT(connp->conn_upper_handle != NULL); 217 218 /* All Solaris components should pass a cred for this operation */ 219 ASSERT(cr != NULL); 220 221 error = squeue_synch_enter(connp, NULL); 222 if (error != 0) { 223 /* Failed to enter */ 224 return (ENOBUFS); 225 } 226 227 error = dccp_do_listen(connp, NULL, 0, backlog, cr, B_FALSE); 228 if (error == 0) { 229 /* XXX:DCCP */ 230 (*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle, 231 SOCK_OPCTL_ENAB_ACCEPT, 232 (uintptr_t)(10)); 233 } else if (error < 0) { 234 if (error == -TOUTSTATE) { 235 error = EINVAL; 236 } else { 237 error = proto_tlitosyserr(-error); 238 } 239 } 240 241 squeue_synch_exit(connp); 242 243 return (error); 244 } 245 246 static int 247 dccp_connect(sock_lower_handle_t proto_handle, const struct sockaddr *sa, 248 socklen_t len, sock_connid_t *id, cred_t *cr) 249 { 250 conn_t *connp = (conn_t *)proto_handle; 251 int error; 252 253 cmn_err(CE_NOTE, "dccp_socket.c: dccp_connect"); 254 255 ASSERT(connp->conn_upper_handle != NULL); 256 257 /* All Solaris components should pass a cred for this operation */ 258 ASSERT(cr != NULL); 259 260 error = proto_verify_ip_addr(connp->conn_family, sa, len); 261 if (error != 0) { 262 return (error); 263 } 264 265 error = squeue_synch_enter(connp, NULL); 266 if (error != 0) { 267 /* Failed to enter */ 268 return (ENOSR); 269 } 270 271 error = dccp_do_connect(connp, sa, len, cr, curproc->p_pid); 272 if (error == 0) { 273 *id = connp->conn_dccp->dccp_connid; 274 } else if (error < 0) { 275 if (error == -TOUTSTATE) { 276 switch (connp->conn_dccp->dccp_state) { 277 case DCCPS_ACK_SENT: 278 error = EALREADY; 279 break; 280 case DCCPS_ESTABLISHED: 281 error = EISCONN; 282 break; 283 case DCCPS_LISTEN: 284 error = EOPNOTSUPP; 285 break; 286 default: 287 error = EINVAL; 288 break; 289 } 290 } else { 291 error = proto_tlitosyserr(-error); 292 } 293 } 294 295 squeue_synch_exit(connp); 296 297 cmn_err(CE_NOTE, "dccp_connect.c: exit %d", error); 298 return ((error == 0) ? EINPROGRESS : error); 299 } 300 301 /* ARGSUSED3 */ 302 static int 303 dccp_getpeername(sock_lower_handle_t proto_handle, struct sockaddr *addr, 304 socklen_t *addrlenp, cred_t *cr) 305 { 306 conn_t *connp = (conn_t *)proto_handle; 307 dccp_t *dccp = connp->conn_dccp; 308 309 cmn_err(CE_NOTE, "dccp_socket.c: dccp_getpeername"); 310 311 /* All Solaris components should pass a cred for this operation */ 312 ASSERT(cr != NULL); 313 314 ASSERT(dccp != NULL); 315 if (dccp->dccp_state < DCCPS_ACK_RCVD) { 316 return (ENOTCONN); 317 } 318 319 return (conn_getpeername(connp, addr, addrlenp)); 320 } 321 322 /* ARGSUSED3 */ 323 static int 324 dccp_getsockname(sock_lower_handle_t proto_handle, struct sockaddr *addr, 325 socklen_t *addrlenp, cred_t *cr) 326 { 327 conn_t *connp = (conn_t *)proto_handle; 328 int error; 329 330 cmn_err(CE_NOTE, "dccp_socket.c: dccp_getsockname"); 331 332 /* All Solaris components should pass a cred for this operation */ 333 ASSERT(cr != NULL); 334 335 /* XXX UDP has locks here, TCP not */ 336 mutex_enter(&connp->conn_lock); 337 error = conn_getsockname(connp, addr, addrlenp); 338 mutex_exit(&connp->conn_lock); 339 340 return (error); 341 } 342 343 static int 344 dccp_getsockopt(sock_lower_handle_t proto_handle, int level, int option_name, 345 void *optvalp, socklen_t *optlen, cred_t *cr) 346 { 347 conn_t *connp = (conn_t *)proto_handle; 348 void *optvalp_buf; 349 t_uscalar_t max_optbuf_len; 350 int len; 351 int error; 352 353 cmn_err(CE_NOTE, "dccp_socket.c: dccp_getsockopt"); 354 355 ASSERT(connp->conn_upper_handle != NULL); 356 357 /* All Solaris components should pass a cred for this operation */ 358 ASSERT(cr != NULL); 359 360 error = proto_opt_check(level, option_name, *optlen, &max_optbuf_len, 361 dccp_opt_obj.odb_opt_des_arr, 362 dccp_opt_obj.odb_opt_arr_cnt, 363 B_FALSE, B_TRUE, cr); 364 if (error != 0) { 365 if (error < 0) { 366 error = proto_tlitosyserr(-error); 367 } 368 return (error); 369 } 370 371 optvalp_buf = kmem_alloc(max_optbuf_len, KM_SLEEP); 372 if (optvalp_buf == NULL) { 373 return (ENOMEM); 374 } 375 376 error = squeue_synch_enter(connp, NULL); 377 if (error == ENOMEM) { 378 kmem_free(optvalp_buf, max_optbuf_len); 379 return (ENOMEM); 380 } 381 382 len = dccp_opt_get(connp, level, option_name, optvalp_buf); 383 squeue_synch_exit(connp); 384 385 if (len == -1) { 386 kmem_free(optvalp_buf, max_optbuf_len); 387 return (EINVAL); 388 } 389 390 t_uscalar_t size = MIN(len, *optlen); 391 392 bcopy(optvalp_buf, optvalp, size); 393 bcopy(&size, optlen, sizeof (size)); 394 395 kmem_free(optvalp_buf, max_optbuf_len); 396 397 return (0); 398 } 399 400 static int 401 dccp_setsockopt(sock_lower_handle_t proto_handle, int level, int option_name, 402 const void *optvalp, socklen_t optlen, cred_t *cr) 403 { 404 conn_t *connp = (conn_t *)proto_handle; 405 int error; 406 407 cmn_err(CE_NOTE, "dccp_socket.c: dccp_setsockopt"); 408 409 ASSERT(connp->conn_upper_handle != NULL); 410 411 /* All Solaris components should pass a cred for this operation */ 412 ASSERT(cr != NULL); 413 414 error = squeue_synch_enter(connp, NULL); 415 if (error == ENOMEM) { 416 return (ENOMEM); 417 } 418 419 error = proto_opt_check(level, option_name, optlen, NULL, 420 dccp_opt_obj.odb_opt_des_arr, 421 dccp_opt_obj.odb_opt_arr_cnt, 422 B_TRUE, B_FALSE, cr); 423 if (error != 0) { 424 if (error < 0) { 425 error = proto_tlitosyserr(-error); 426 } 427 squeue_synch_exit(connp); 428 return (error); 429 } 430 431 error = dccp_opt_set(connp, SETFN_OPTCOM_NEGOTIATE, level, option_name, 432 optlen, (uchar_t *)optvalp, (uint_t *)&optlen, (uchar_t *)optvalp, 433 NULL, cr); 434 squeue_synch_exit(connp); 435 436 ASSERT(error >= 0); 437 438 return (error); 439 } 440 441 /* ARGSUSED */ 442 static int 443 dccp_send(sock_lower_handle_t proto_handle, mblk_t *mp, struct nmsghdr *msg, 444 cred_t *cr) 445 { 446 conn_t *connp = (conn_t *)proto_handle; 447 dccp_t *dccp; 448 uint32_t msize; 449 int32_t dccpstate; 450 451 cmn_err(CE_NOTE, "dccp_socket.c: dccp_send"); 452 453 /* All Solaris components should pass a cred for this operation */ 454 ASSERT(cr != NULL); 455 456 ASSERT(connp->conn_ref >= 2); 457 ASSERT(connp->conn_upper_handle != NULL); 458 459 if (msg->msg_controllen != 0) { 460 freemsg(mp); 461 return (EOPNOTSUPP); 462 } 463 464 switch (DB_TYPE(mp)) { 465 case M_DATA: 466 dccp = connp->conn_dccp; 467 ASSERT(dccp != NULL); 468 469 dccpstate = dccp->dccp_state; 470 471 /* XXX */ 472 473 msize = msgdsize(mp); 474 475 if (msg->msg_flags & MSG_OOB) { 476 SQUEUE_ENTER_ONE(connp->conn_sqp, mp, dccp_output_urgent, 477 connp, NULL, dccp_squeue_flag, SQTAG_DCCP_OUTPUT); 478 } else { 479 SQUEUE_ENTER_ONE(connp->conn_sqp, mp, dccp_output, 480 connp, NULL, dccp_squeue_flag, SQTAG_DCCP_OUTPUT); 481 } 482 483 return (0); 484 485 default: 486 ASSERT(0); 487 } 488 489 freemsg(mp); 490 491 return (0); 492 } 493 494 /* ARGSUSED */ 495 static int 496 dccp_shutdown(sock_lower_handle_t proto_handle, int how, cred_t *cr) 497 { 498 conn_t *connp = (conn_t *)proto_handle; 499 dccp_t *dccp = connp->conn_dccp; 500 501 cmn_err(CE_NOTE, "dccp_socket.c: dccp_shutdown"); 502 503 /* All Solaris components should pass a cred for this operation. */ 504 ASSERT(cr != NULL); 505 506 ASSERT(connp->conn_upper_handle != NULL); 507 508 509 return (ENOTSUP); 510 } 511 512 static void 513 dccp_clr_flowctrl(sock_lower_handle_t proto_handle) 514 { 515 conn_t *connp = (conn_t *)proto_handle; 516 dccp_t *dccp = connp->conn_dccp; 517 mblk_t *mp; 518 int error; 519 520 ASSERT(connp->conn_upper_handle != NULL); 521 522 cmn_err(CE_NOTE, "dccp_socket.c: dccp_clr_flowctrl"); 523 524 error = squeue_synch_enter(connp, mp); 525 526 squeue_synch_exit(connp); 527 } 528 529 /* ARGSUSED */ 530 static int 531 dccp_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg, 532 int mode, int32_t *rvalp, cred_t *cr) 533 { 534 conn_t *connp = (conn_t *)proto_handle; 535 int error; 536 537 cmn_err(CE_NOTE, "dccp_socket.c: dccp_ioctl"); 538 539 ASSERT(connp->conn_upper_handle != NULL); 540 541 /* All Solaris components should pass a cred for this operation. */ 542 ASSERT(cr != NULL); 543 544 return (ENOTSUP); 545 } 546 547 /* ARGSUSED */ 548 static int 549 dccp_close(sock_lower_handle_t proto_handle, int flags, cred_t *cr) 550 { 551 conn_t *connp = (conn_t *)proto_handle; 552 553 cmn_err(CE_NOTE, "dccp_socket.c: dccp_close\n"); 554 555 ASSERT(connp->conn_upper_handle != NULL); 556 557 /* All Solaris components should pass a cred for this operation */ 558 ASSERT(cr != NULL); 559 560 dccp_close_common(connp, flags); 561 562 ip_free_helper_stream(connp); 563 564 CONN_DEC_REF(connp); 565 566 return (EINPROGRESS); 567 } 568 569 570 /* 571 * Socket create function. 572 */ 573 sock_lower_handle_t 574 dccp_create(int family, int type, int proto, sock_downcalls_t **sockdowncalls, 575 uint_t *smodep, int *errorp, int flags, cred_t *credp) 576 { 577 conn_t *connp; 578 boolean_t isv6; 579 580 /* XXX (type != SOCK_STREAM */ 581 if ((family != AF_INET && family != AF_INET6) || 582 (proto != 0 && proto != IPPROTO_DCCP)) { 583 *errorp = EPROTONOSUPPORT; 584 return (NULL); 585 } 586 587 cmn_err(CE_NOTE, "dccp_socket: dccp_create\n"); 588 589 isv6 = family == AF_INET6 ? B_TRUE: B_FALSE; 590 connp = dccp_create_common(credp, isv6, B_TRUE, errorp); 591 if (connp == NULL) { 592 return (NULL); 593 } 594 595 /* 596 * Increment ref for DCCP connection. 597 */ 598 mutex_enter(&connp->conn_lock); 599 CONN_INC_REF_LOCKED(connp); 600 ASSERT(connp->conn_ref == 2); 601 connp->conn_state_flags &= ~CONN_INCIPIENT; 602 connp->conn_flags |= IPCL_NONSTR; 603 mutex_exit(&connp->conn_lock); 604 605 ASSERT(errorp != NULL); 606 *errorp = 0; 607 *sockdowncalls = &sock_dccp_downcalls; 608 *smodep = SM_CONNREQUIRED | SM_EXDATA | SM_ACCEPTSUPP | 609 SM_SENDFILESUPP; 610 611 return ((sock_lower_handle_t)connp); 612 } 613 614 int 615 dccp_fallback(sock_lower_handle_t proto_handle, queue_t *q, 616 boolean_t issocket, so_proto_quiesced_cb_t quiesced_cb, 617 sock_quiesce_arg_t *arg) 618 { 619 cmn_err(CE_NOTE, "dccp_socket: dccp_fallback\n"); 620 621 return (0); 622 }