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