1*0f1702c5SYu Xiangning /* 2*0f1702c5SYu Xiangning * CDDL HEADER START 3*0f1702c5SYu Xiangning * 4*0f1702c5SYu Xiangning * The contents of this file are subject to the terms of the 5*0f1702c5SYu Xiangning * Common Development and Distribution License (the "License"). 6*0f1702c5SYu Xiangning * You may not use this file except in compliance with the License. 7*0f1702c5SYu Xiangning * 8*0f1702c5SYu Xiangning * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*0f1702c5SYu Xiangning * or http://www.opensolaris.org/os/licensing. 10*0f1702c5SYu Xiangning * See the License for the specific language governing permissions 11*0f1702c5SYu Xiangning * and limitations under the License. 12*0f1702c5SYu Xiangning * 13*0f1702c5SYu Xiangning * When distributing Covered Code, include this CDDL HEADER in each 14*0f1702c5SYu Xiangning * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*0f1702c5SYu Xiangning * If applicable, add the following below this CDDL HEADER, with the 16*0f1702c5SYu Xiangning * fields enclosed by brackets "[]" replaced with your own identifying 17*0f1702c5SYu Xiangning * information: Portions Copyright [yyyy] [name of copyright owner] 18*0f1702c5SYu Xiangning * 19*0f1702c5SYu Xiangning * CDDL HEADER END 20*0f1702c5SYu Xiangning */ 21*0f1702c5SYu Xiangning /* 22*0f1702c5SYu Xiangning * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*0f1702c5SYu Xiangning * Use is subject to license terms. 24*0f1702c5SYu Xiangning */ 25*0f1702c5SYu Xiangning 26*0f1702c5SYu Xiangning #include <sys/types.h> 27*0f1702c5SYu Xiangning #include <inet/common.h> 28*0f1702c5SYu Xiangning #include <sys/stream.h> 29*0f1702c5SYu Xiangning #include <sys/stropts.h> 30*0f1702c5SYu Xiangning #include <sys/strsun.h> 31*0f1702c5SYu Xiangning #include <sys/sysmacros.h> 32*0f1702c5SYu Xiangning #include <sys/stropts.h> 33*0f1702c5SYu Xiangning #include <sys/strsubr.h> 34*0f1702c5SYu Xiangning #include <sys/tpicommon.h> 35*0f1702c5SYu Xiangning #include <sys/socket_proto.h> 36*0f1702c5SYu Xiangning #include <sys/policy.h> 37*0f1702c5SYu Xiangning #include <inet/optcom.h> 38*0f1702c5SYu Xiangning #include <inet/ipclassifier.h> 39*0f1702c5SYu Xiangning 40*0f1702c5SYu Xiangning boolean_t 41*0f1702c5SYu Xiangning proto_set_rx_hiwat(queue_t *q, conn_t *connp, size_t size) 42*0f1702c5SYu Xiangning { 43*0f1702c5SYu Xiangning 44*0f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 45*0f1702c5SYu Xiangning struct sock_proto_props sopp; 46*0f1702c5SYu Xiangning 47*0f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_RCVHIWAT; 48*0f1702c5SYu Xiangning sopp.sopp_rxhiwat = size; 49*0f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 50*0f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 51*0f1702c5SYu Xiangning } else { 52*0f1702c5SYu Xiangning MBLKP mp; 53*0f1702c5SYu Xiangning struct stroptions *stropt; 54*0f1702c5SYu Xiangning 55*0f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 56*0f1702c5SYu Xiangning return (B_FALSE); 57*0f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS; 58*0f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt); 59*0f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr; 60*0f1702c5SYu Xiangning stropt->so_flags = SO_HIWAT; 61*0f1702c5SYu Xiangning stropt->so_hiwat = size; 62*0f1702c5SYu Xiangning putnext(q, mp); 63*0f1702c5SYu Xiangning } 64*0f1702c5SYu Xiangning return (B_TRUE); 65*0f1702c5SYu Xiangning } 66*0f1702c5SYu Xiangning 67*0f1702c5SYu Xiangning boolean_t 68*0f1702c5SYu Xiangning proto_set_rx_lowat(queue_t *q, conn_t *connp, size_t size) 69*0f1702c5SYu Xiangning { 70*0f1702c5SYu Xiangning 71*0f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 72*0f1702c5SYu Xiangning struct sock_proto_props sopp; 73*0f1702c5SYu Xiangning 74*0f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_RCVLOWAT; 75*0f1702c5SYu Xiangning sopp.sopp_rxlowat = size; 76*0f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 77*0f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 78*0f1702c5SYu Xiangning } else { 79*0f1702c5SYu Xiangning MBLKP mp; 80*0f1702c5SYu Xiangning struct stroptions *stropt; 81*0f1702c5SYu Xiangning 82*0f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 83*0f1702c5SYu Xiangning return (B_FALSE); 84*0f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS; 85*0f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt); 86*0f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr; 87*0f1702c5SYu Xiangning stropt->so_flags = SO_LOWAT; 88*0f1702c5SYu Xiangning stropt->so_lowat = size; 89*0f1702c5SYu Xiangning putnext(q, mp); 90*0f1702c5SYu Xiangning } 91*0f1702c5SYu Xiangning return (B_TRUE); 92*0f1702c5SYu Xiangning } 93*0f1702c5SYu Xiangning 94*0f1702c5SYu Xiangning /* 95*0f1702c5SYu Xiangning * Set maximum packet size. This is the maximum amount of data the protocol 96*0f1702c5SYu Xiangning * wants to be given at any time, Larger data needs to be broken in multiples 97*0f1702c5SYu Xiangning * of maximum packet size and given to the protocol one at a time. 98*0f1702c5SYu Xiangning */ 99*0f1702c5SYu Xiangning boolean_t 100*0f1702c5SYu Xiangning proto_set_maxpsz(queue_t *q, conn_t *connp, size_t size) 101*0f1702c5SYu Xiangning { 102*0f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 103*0f1702c5SYu Xiangning struct sock_proto_props sopp; 104*0f1702c5SYu Xiangning 105*0f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_MAXPSZ; 106*0f1702c5SYu Xiangning sopp.sopp_maxpsz = size; 107*0f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 108*0f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 109*0f1702c5SYu Xiangning return (B_TRUE); 110*0f1702c5SYu Xiangning } else { 111*0f1702c5SYu Xiangning struct stdata *stp; 112*0f1702c5SYu Xiangning queue_t *wq; 113*0f1702c5SYu Xiangning stp = STREAM(q); 114*0f1702c5SYu Xiangning 115*0f1702c5SYu Xiangning /* 116*0f1702c5SYu Xiangning * At this point change of a queue parameter is not allowed 117*0f1702c5SYu Xiangning * when a multiplexor is sitting on top. 118*0f1702c5SYu Xiangning */ 119*0f1702c5SYu Xiangning if (stp == NULL || stp->sd_flag & STPLEX) 120*0f1702c5SYu Xiangning return (B_FALSE); 121*0f1702c5SYu Xiangning 122*0f1702c5SYu Xiangning claimstr(stp->sd_wrq); 123*0f1702c5SYu Xiangning wq = stp->sd_wrq->q_next; 124*0f1702c5SYu Xiangning ASSERT(wq != NULL); 125*0f1702c5SYu Xiangning (void) strqset(wq, QMAXPSZ, 0, size); 126*0f1702c5SYu Xiangning releasestr(stp->sd_wrq); 127*0f1702c5SYu Xiangning return (B_TRUE); 128*0f1702c5SYu Xiangning } 129*0f1702c5SYu Xiangning } 130*0f1702c5SYu Xiangning 131*0f1702c5SYu Xiangning /* ARGSUSED */ 132*0f1702c5SYu Xiangning boolean_t 133*0f1702c5SYu Xiangning proto_set_tx_maxblk(queue_t *q, conn_t *connp, ssize_t size) 134*0f1702c5SYu Xiangning { 135*0f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 136*0f1702c5SYu Xiangning struct sock_proto_props sopp; 137*0f1702c5SYu Xiangning 138*0f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_MAXBLK; 139*0f1702c5SYu Xiangning sopp.sopp_maxblk = size; 140*0f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 141*0f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 142*0f1702c5SYu Xiangning } else { 143*0f1702c5SYu Xiangning MBLKP mp; 144*0f1702c5SYu Xiangning struct stroptions *stropt; 145*0f1702c5SYu Xiangning 146*0f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 147*0f1702c5SYu Xiangning return (B_FALSE); 148*0f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS; 149*0f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt); 150*0f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr; 151*0f1702c5SYu Xiangning stropt->so_flags = SO_MAXBLK; 152*0f1702c5SYu Xiangning stropt->so_maxblk = size; 153*0f1702c5SYu Xiangning putnext(q, mp); 154*0f1702c5SYu Xiangning } 155*0f1702c5SYu Xiangning return (B_TRUE); 156*0f1702c5SYu Xiangning } 157*0f1702c5SYu Xiangning 158*0f1702c5SYu Xiangning boolean_t 159*0f1702c5SYu Xiangning proto_set_tx_copyopt(queue_t *q, conn_t *connp, int copyopt) 160*0f1702c5SYu Xiangning { 161*0f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 162*0f1702c5SYu Xiangning struct sock_proto_props sopp; 163*0f1702c5SYu Xiangning 164*0f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_ZCOPY; 165*0f1702c5SYu Xiangning sopp.sopp_zcopyflag = (ushort_t)copyopt; 166*0f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 167*0f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 168*0f1702c5SYu Xiangning } else { 169*0f1702c5SYu Xiangning MBLKP mp; 170*0f1702c5SYu Xiangning struct stroptions *stropt; 171*0f1702c5SYu Xiangning 172*0f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 173*0f1702c5SYu Xiangning return (B_FALSE); 174*0f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS; 175*0f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt); 176*0f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr; 177*0f1702c5SYu Xiangning stropt->so_flags = SO_COPYOPT; 178*0f1702c5SYu Xiangning stropt->so_copyopt = (ushort_t)copyopt; 179*0f1702c5SYu Xiangning putnext(q, mp); 180*0f1702c5SYu Xiangning } 181*0f1702c5SYu Xiangning return (B_TRUE); 182*0f1702c5SYu Xiangning } 183*0f1702c5SYu Xiangning 184*0f1702c5SYu Xiangning boolean_t 185*0f1702c5SYu Xiangning proto_set_tx_wroff(queue_t *q, conn_t *connp, size_t size) 186*0f1702c5SYu Xiangning { 187*0f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 188*0f1702c5SYu Xiangning struct sock_proto_props sopp; 189*0f1702c5SYu Xiangning 190*0f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_WROFF; 191*0f1702c5SYu Xiangning sopp.sopp_wroff = size; 192*0f1702c5SYu Xiangning 193*0f1702c5SYu Xiangning /* XXX workaround for CR6757374 */ 194*0f1702c5SYu Xiangning if (connp->conn_upper_handle != NULL) 195*0f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 196*0f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 197*0f1702c5SYu Xiangning } else { 198*0f1702c5SYu Xiangning 199*0f1702c5SYu Xiangning MBLKP mp; 200*0f1702c5SYu Xiangning struct stroptions *stropt; 201*0f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 202*0f1702c5SYu Xiangning return (B_FALSE); 203*0f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS; 204*0f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt); 205*0f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr; 206*0f1702c5SYu Xiangning stropt->so_flags = SO_WROFF; 207*0f1702c5SYu Xiangning stropt->so_wroff = (ushort_t)size; 208*0f1702c5SYu Xiangning putnext(q, mp); 209*0f1702c5SYu Xiangning } 210*0f1702c5SYu Xiangning return (B_TRUE); 211*0f1702c5SYu Xiangning } 212*0f1702c5SYu Xiangning 213*0f1702c5SYu Xiangning /* 214*0f1702c5SYu Xiangning * set OOBINLINE processing on the socket 215*0f1702c5SYu Xiangning */ 216*0f1702c5SYu Xiangning void 217*0f1702c5SYu Xiangning proto_set_rx_oob_opt(conn_t *connp, boolean_t onoff) 218*0f1702c5SYu Xiangning { 219*0f1702c5SYu Xiangning struct sock_proto_props sopp; 220*0f1702c5SYu Xiangning 221*0f1702c5SYu Xiangning ASSERT(IPCL_IS_NONSTR(connp)); 222*0f1702c5SYu Xiangning 223*0f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_OOBINLINE; 224*0f1702c5SYu Xiangning sopp.sopp_oobinline = onoff; 225*0f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 226*0f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 227*0f1702c5SYu Xiangning } 228*0f1702c5SYu Xiangning 229*0f1702c5SYu Xiangning /* 230*0f1702c5SYu Xiangning * Translate a TLI(/XTI) error into a system error as best we can. 231*0f1702c5SYu Xiangning */ 232*0f1702c5SYu Xiangning static const int tli_errs[] = { 233*0f1702c5SYu Xiangning 0, /* no error */ 234*0f1702c5SYu Xiangning EADDRNOTAVAIL, /* TBADADDR */ 235*0f1702c5SYu Xiangning ENOPROTOOPT, /* TBADOPT */ 236*0f1702c5SYu Xiangning EACCES, /* TACCES */ 237*0f1702c5SYu Xiangning EBADF, /* TBADF */ 238*0f1702c5SYu Xiangning EADDRNOTAVAIL, /* TNOADDR */ 239*0f1702c5SYu Xiangning EPROTO, /* TOUTSTATE */ 240*0f1702c5SYu Xiangning ECONNABORTED, /* TBADSEQ */ 241*0f1702c5SYu Xiangning 0, /* TSYSERR - will never get */ 242*0f1702c5SYu Xiangning EPROTO, /* TLOOK - should never be sent by transport */ 243*0f1702c5SYu Xiangning EMSGSIZE, /* TBADDATA */ 244*0f1702c5SYu Xiangning EMSGSIZE, /* TBUFOVFLW */ 245*0f1702c5SYu Xiangning EPROTO, /* TFLOW */ 246*0f1702c5SYu Xiangning EWOULDBLOCK, /* TNODATA */ 247*0f1702c5SYu Xiangning EPROTO, /* TNODIS */ 248*0f1702c5SYu Xiangning EPROTO, /* TNOUDERR */ 249*0f1702c5SYu Xiangning EINVAL, /* TBADFLAG */ 250*0f1702c5SYu Xiangning EPROTO, /* TNOREL */ 251*0f1702c5SYu Xiangning EOPNOTSUPP, /* TNOTSUPPORT */ 252*0f1702c5SYu Xiangning EPROTO, /* TSTATECHNG */ 253*0f1702c5SYu Xiangning /* following represent error namespace expansion with XTI */ 254*0f1702c5SYu Xiangning EPROTO, /* TNOSTRUCTYPE - never sent by transport */ 255*0f1702c5SYu Xiangning EPROTO, /* TBADNAME - never sent by transport */ 256*0f1702c5SYu Xiangning EPROTO, /* TBADQLEN - never sent by transport */ 257*0f1702c5SYu Xiangning EADDRINUSE, /* TADDRBUSY */ 258*0f1702c5SYu Xiangning EBADF, /* TINDOUT */ 259*0f1702c5SYu Xiangning EBADF, /* TPROVMISMATCH */ 260*0f1702c5SYu Xiangning EBADF, /* TRESQLEN */ 261*0f1702c5SYu Xiangning EBADF, /* TRESADDR */ 262*0f1702c5SYu Xiangning EPROTO, /* TQFULL - never sent by transport */ 263*0f1702c5SYu Xiangning EPROTO, /* TPROTO */ 264*0f1702c5SYu Xiangning }; 265*0f1702c5SYu Xiangning 266*0f1702c5SYu Xiangning int 267*0f1702c5SYu Xiangning proto_tlitosyserr(int terr) 268*0f1702c5SYu Xiangning { 269*0f1702c5SYu Xiangning ASSERT(terr != TSYSERR); 270*0f1702c5SYu Xiangning if (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0]))) 271*0f1702c5SYu Xiangning return (EPROTO); 272*0f1702c5SYu Xiangning else 273*0f1702c5SYu Xiangning return (tli_errs[terr]); 274*0f1702c5SYu Xiangning } 275*0f1702c5SYu Xiangning 276*0f1702c5SYu Xiangning /* 277*0f1702c5SYu Xiangning * Verify that address is suitable for connect/sendmsg and is aligned properly 278*0f1702c5SYu Xiangning * Since this is a generic function we do not test for port being zero 279*0f1702c5SYu Xiangning * as some protocols like icmp do not require a port 280*0f1702c5SYu Xiangning */ 281*0f1702c5SYu Xiangning int 282*0f1702c5SYu Xiangning proto_verify_ip_addr(int family, const struct sockaddr *name, socklen_t namelen) 283*0f1702c5SYu Xiangning { 284*0f1702c5SYu Xiangning 285*0f1702c5SYu Xiangning if (name == NULL || !OK_32PTR((char *)name)) 286*0f1702c5SYu Xiangning return (EINVAL); 287*0f1702c5SYu Xiangning 288*0f1702c5SYu Xiangning switch (family) { 289*0f1702c5SYu Xiangning case AF_INET: 290*0f1702c5SYu Xiangning if (name->sa_family != AF_INET) { 291*0f1702c5SYu Xiangning return (EAFNOSUPPORT); 292*0f1702c5SYu Xiangning } 293*0f1702c5SYu Xiangning 294*0f1702c5SYu Xiangning if (namelen != (socklen_t)sizeof (struct sockaddr_in)) { 295*0f1702c5SYu Xiangning return (EINVAL); 296*0f1702c5SYu Xiangning } 297*0f1702c5SYu Xiangning break; 298*0f1702c5SYu Xiangning case AF_INET6: { 299*0f1702c5SYu Xiangning #ifdef DEBUG 300*0f1702c5SYu Xiangning struct sockaddr_in6 *sin6; 301*0f1702c5SYu Xiangning #endif /* DEBUG */ 302*0f1702c5SYu Xiangning 303*0f1702c5SYu Xiangning if (name->sa_family != AF_INET6) { 304*0f1702c5SYu Xiangning return (EAFNOSUPPORT); 305*0f1702c5SYu Xiangning } 306*0f1702c5SYu Xiangning if (namelen != (socklen_t)sizeof (struct sockaddr_in6)) { 307*0f1702c5SYu Xiangning return (EINVAL); 308*0f1702c5SYu Xiangning } 309*0f1702c5SYu Xiangning #ifdef DEBUG 310*0f1702c5SYu Xiangning /* Verify that apps don't forget to clear sin6_scope_id etc */ 311*0f1702c5SYu Xiangning sin6 = (struct sockaddr_in6 *)name; 312*0f1702c5SYu Xiangning if (sin6->sin6_scope_id != 0 && 313*0f1702c5SYu Xiangning !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) { 314*0f1702c5SYu Xiangning zcmn_err(getzoneid(), CE_WARN, 315*0f1702c5SYu Xiangning "connect/send* with uninitialized sin6_scope_id " 316*0f1702c5SYu Xiangning "(%d) on socket. Pid = %d\n", 317*0f1702c5SYu Xiangning (int)sin6->sin6_scope_id, (int)curproc->p_pid); 318*0f1702c5SYu Xiangning } 319*0f1702c5SYu Xiangning #endif /* DEBUG */ 320*0f1702c5SYu Xiangning break; 321*0f1702c5SYu Xiangning } 322*0f1702c5SYu Xiangning default: 323*0f1702c5SYu Xiangning return (EINVAL); 324*0f1702c5SYu Xiangning } 325*0f1702c5SYu Xiangning 326*0f1702c5SYu Xiangning return (0); 327*0f1702c5SYu Xiangning } 328*0f1702c5SYu Xiangning 329*0f1702c5SYu Xiangning /* 330*0f1702c5SYu Xiangning * Do a lookup of the options in the array. 331*0f1702c5SYu Xiangning * Rerurn NULL if there isn't a match. 332*0f1702c5SYu Xiangning */ 333*0f1702c5SYu Xiangning opdes_t * 334*0f1702c5SYu Xiangning proto_opt_lookup(t_uscalar_t level, t_uscalar_t name, opdes_t *opt_arr, 335*0f1702c5SYu Xiangning uint_t opt_arr_cnt) 336*0f1702c5SYu Xiangning { 337*0f1702c5SYu Xiangning opdes_t *optd; 338*0f1702c5SYu Xiangning 339*0f1702c5SYu Xiangning for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; 340*0f1702c5SYu Xiangning optd++) { 341*0f1702c5SYu Xiangning if (level == (uint_t)optd->opdes_level && 342*0f1702c5SYu Xiangning name == (uint_t)optd->opdes_name) 343*0f1702c5SYu Xiangning return (optd); 344*0f1702c5SYu Xiangning } 345*0f1702c5SYu Xiangning return (NULL); 346*0f1702c5SYu Xiangning } 347*0f1702c5SYu Xiangning 348*0f1702c5SYu Xiangning /* 349*0f1702c5SYu Xiangning * Do a lookup of the options in the array and do permission and length checking 350*0f1702c5SYu Xiangning * Returns zero if there is no error (note: for non-tpi-providers not being able 351*0f1702c5SYu Xiangning * to find the option is not an error). TPI errors are returned as -ve. 352*0f1702c5SYu Xiangning */ 353*0f1702c5SYu Xiangning int 354*0f1702c5SYu Xiangning proto_opt_check(int level, int name, int len, t_uscalar_t *max_len, 355*0f1702c5SYu Xiangning opdes_t *opt_arr, uint_t opt_arr_cnt, boolean_t topmost_tpiprovider, 356*0f1702c5SYu Xiangning boolean_t negotiate, boolean_t check, cred_t *cr) 357*0f1702c5SYu Xiangning { 358*0f1702c5SYu Xiangning opdes_t *optd; 359*0f1702c5SYu Xiangning 360*0f1702c5SYu Xiangning /* Find the option in the opt_arr. */ 361*0f1702c5SYu Xiangning if ((optd = proto_opt_lookup(level, name, opt_arr, opt_arr_cnt)) == 362*0f1702c5SYu Xiangning NULL) { 363*0f1702c5SYu Xiangning /* 364*0f1702c5SYu Xiangning * Not found, that is a bad thing if 365*0f1702c5SYu Xiangning * the caller is a tpi provider 366*0f1702c5SYu Xiangning */ 367*0f1702c5SYu Xiangning if (topmost_tpiprovider) 368*0f1702c5SYu Xiangning return (-TBADOPT); 369*0f1702c5SYu Xiangning else 370*0f1702c5SYu Xiangning return (0); /* skip unmodified */ 371*0f1702c5SYu Xiangning } 372*0f1702c5SYu Xiangning 373*0f1702c5SYu Xiangning /* Additional checks dependent on operation. */ 374*0f1702c5SYu Xiangning if (negotiate) { 375*0f1702c5SYu Xiangning /* Cannot be true at the same time */ 376*0f1702c5SYu Xiangning ASSERT(check == B_FALSE); 377*0f1702c5SYu Xiangning 378*0f1702c5SYu Xiangning if (!OA_WRITE_OR_EXECUTE(optd, cr)) { 379*0f1702c5SYu Xiangning /* can't negotiate option */ 380*0f1702c5SYu Xiangning if (!(OA_MATCHED_PRIV(optd, cr)) && 381*0f1702c5SYu Xiangning OA_WX_ANYPRIV(optd)) { 382*0f1702c5SYu Xiangning /* 383*0f1702c5SYu Xiangning * not privileged but privilege 384*0f1702c5SYu Xiangning * will help negotiate option. 385*0f1702c5SYu Xiangning */ 386*0f1702c5SYu Xiangning return (-TACCES); 387*0f1702c5SYu Xiangning } else { 388*0f1702c5SYu Xiangning return (-TBADOPT); 389*0f1702c5SYu Xiangning } 390*0f1702c5SYu Xiangning } 391*0f1702c5SYu Xiangning /* 392*0f1702c5SYu Xiangning * Verify size for options 393*0f1702c5SYu Xiangning * Note: For retaining compatibility with historical 394*0f1702c5SYu Xiangning * behavior, variable lengths options will have their 395*0f1702c5SYu Xiangning * length verified in the setfn() processing. 396*0f1702c5SYu Xiangning * In order to be compatible with SunOS 4.X we return 397*0f1702c5SYu Xiangning * EINVAL errors for bad lengths. 398*0f1702c5SYu Xiangning */ 399*0f1702c5SYu Xiangning if (!(optd->opdes_props & OP_VARLEN)) { 400*0f1702c5SYu Xiangning /* fixed length - size must match */ 401*0f1702c5SYu Xiangning if (len != optd->opdes_size) { 402*0f1702c5SYu Xiangning return (EINVAL); 403*0f1702c5SYu Xiangning } 404*0f1702c5SYu Xiangning } 405*0f1702c5SYu Xiangning } else { 406*0f1702c5SYu Xiangning if (check) { 407*0f1702c5SYu Xiangning if (!OA_RWX_ANYPRIV(optd)) 408*0f1702c5SYu Xiangning /* any of "rwx" permission but not none */ 409*0f1702c5SYu Xiangning return (-TBADOPT); 410*0f1702c5SYu Xiangning } 411*0f1702c5SYu Xiangning /* 412*0f1702c5SYu Xiangning * XXX Change the comments. 413*0f1702c5SYu Xiangning * 414*0f1702c5SYu Xiangning * XXX Since T_CURRENT was not there in TLI and the 415*0f1702c5SYu Xiangning * official TLI inspired TPI standard, getsockopt() 416*0f1702c5SYu Xiangning * API uses T_CHECK (for T_CURRENT semantics) 417*0f1702c5SYu Xiangning * The following fallthru makes sense because of its 418*0f1702c5SYu Xiangning * historical use as semantic equivalent to T_CURRENT. 419*0f1702c5SYu Xiangning */ 420*0f1702c5SYu Xiangning /* FALLTHRU */ 421*0f1702c5SYu Xiangning if (!OA_READ_PERMISSION(optd, cr)) { 422*0f1702c5SYu Xiangning /* can't read option value */ 423*0f1702c5SYu Xiangning if (!(OA_MATCHED_PRIV(optd, cr)) && 424*0f1702c5SYu Xiangning OA_R_ANYPRIV(optd)) { 425*0f1702c5SYu Xiangning /* 426*0f1702c5SYu Xiangning * not privileged but privilege 427*0f1702c5SYu Xiangning * will help in reading option value. 428*0f1702c5SYu Xiangning */ 429*0f1702c5SYu Xiangning return (-TACCES); 430*0f1702c5SYu Xiangning } else { 431*0f1702c5SYu Xiangning return (-TBADOPT); 432*0f1702c5SYu Xiangning } 433*0f1702c5SYu Xiangning } 434*0f1702c5SYu Xiangning } 435*0f1702c5SYu Xiangning if (max_len != NULL) 436*0f1702c5SYu Xiangning *max_len = optd->opdes_size; 437*0f1702c5SYu Xiangning 438*0f1702c5SYu Xiangning /* We liked it. Keep going. */ 439*0f1702c5SYu Xiangning return (0); 440*0f1702c5SYu Xiangning } 441