10f1702c5SYu Xiangning /*
20f1702c5SYu Xiangning * CDDL HEADER START
30f1702c5SYu Xiangning *
40f1702c5SYu Xiangning * The contents of this file are subject to the terms of the
50f1702c5SYu Xiangning * Common Development and Distribution License (the "License").
60f1702c5SYu Xiangning * You may not use this file except in compliance with the License.
70f1702c5SYu Xiangning *
80f1702c5SYu Xiangning * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90f1702c5SYu Xiangning * or http://www.opensolaris.org/os/licensing.
100f1702c5SYu Xiangning * See the License for the specific language governing permissions
110f1702c5SYu Xiangning * and limitations under the License.
120f1702c5SYu Xiangning *
130f1702c5SYu Xiangning * When distributing Covered Code, include this CDDL HEADER in each
140f1702c5SYu Xiangning * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150f1702c5SYu Xiangning * If applicable, add the following below this CDDL HEADER, with the
160f1702c5SYu Xiangning * fields enclosed by brackets "[]" replaced with your own identifying
170f1702c5SYu Xiangning * information: Portions Copyright [yyyy] [name of copyright owner]
180f1702c5SYu Xiangning *
190f1702c5SYu Xiangning * CDDL HEADER END
200f1702c5SYu Xiangning */
210f1702c5SYu Xiangning /*
22*bd670b35SErik Nordmark * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230f1702c5SYu Xiangning * Use is subject to license terms.
240f1702c5SYu Xiangning */
250f1702c5SYu Xiangning
260f1702c5SYu Xiangning #include <sys/types.h>
270f1702c5SYu Xiangning #include <inet/common.h>
280f1702c5SYu Xiangning #include <sys/stream.h>
290f1702c5SYu Xiangning #include <sys/stropts.h>
300f1702c5SYu Xiangning #include <sys/strsun.h>
310f1702c5SYu Xiangning #include <sys/sysmacros.h>
320f1702c5SYu Xiangning #include <sys/stropts.h>
330f1702c5SYu Xiangning #include <sys/strsubr.h>
340f1702c5SYu Xiangning #include <sys/tpicommon.h>
350f1702c5SYu Xiangning #include <sys/socket_proto.h>
360f1702c5SYu Xiangning #include <sys/policy.h>
370f1702c5SYu Xiangning #include <inet/optcom.h>
380f1702c5SYu Xiangning #include <inet/ipclassifier.h>
390f1702c5SYu Xiangning
400f1702c5SYu Xiangning boolean_t
proto_set_rx_hiwat(queue_t * q,conn_t * connp,size_t size)410f1702c5SYu Xiangning proto_set_rx_hiwat(queue_t *q, conn_t *connp, size_t size)
420f1702c5SYu Xiangning {
430f1702c5SYu Xiangning
440f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) {
450f1702c5SYu Xiangning struct sock_proto_props sopp;
460f1702c5SYu Xiangning
470f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_RCVHIWAT;
480f1702c5SYu Xiangning sopp.sopp_rxhiwat = size;
490f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props)
500f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp);
510f1702c5SYu Xiangning } else {
520f1702c5SYu Xiangning MBLKP mp;
530f1702c5SYu Xiangning struct stroptions *stropt;
540f1702c5SYu Xiangning
550f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
560f1702c5SYu Xiangning return (B_FALSE);
570f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS;
580f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt);
590f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr;
600f1702c5SYu Xiangning stropt->so_flags = SO_HIWAT;
610f1702c5SYu Xiangning stropt->so_hiwat = size;
620f1702c5SYu Xiangning putnext(q, mp);
630f1702c5SYu Xiangning }
640f1702c5SYu Xiangning return (B_TRUE);
650f1702c5SYu Xiangning }
660f1702c5SYu Xiangning
670f1702c5SYu Xiangning boolean_t
proto_set_rx_lowat(queue_t * q,conn_t * connp,size_t size)680f1702c5SYu Xiangning proto_set_rx_lowat(queue_t *q, conn_t *connp, size_t size)
690f1702c5SYu Xiangning {
700f1702c5SYu Xiangning
710f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) {
720f1702c5SYu Xiangning struct sock_proto_props sopp;
730f1702c5SYu Xiangning
740f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_RCVLOWAT;
750f1702c5SYu Xiangning sopp.sopp_rxlowat = size;
760f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props)
770f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp);
780f1702c5SYu Xiangning } else {
790f1702c5SYu Xiangning MBLKP mp;
800f1702c5SYu Xiangning struct stroptions *stropt;
810f1702c5SYu Xiangning
820f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
830f1702c5SYu Xiangning return (B_FALSE);
840f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS;
850f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt);
860f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr;
870f1702c5SYu Xiangning stropt->so_flags = SO_LOWAT;
880f1702c5SYu Xiangning stropt->so_lowat = size;
890f1702c5SYu Xiangning putnext(q, mp);
900f1702c5SYu Xiangning }
910f1702c5SYu Xiangning return (B_TRUE);
920f1702c5SYu Xiangning }
930f1702c5SYu Xiangning
940f1702c5SYu Xiangning /*
950f1702c5SYu Xiangning * Set maximum packet size. This is the maximum amount of data the protocol
960f1702c5SYu Xiangning * wants to be given at any time, Larger data needs to be broken in multiples
970f1702c5SYu Xiangning * of maximum packet size and given to the protocol one at a time.
980f1702c5SYu Xiangning */
990f1702c5SYu Xiangning boolean_t
proto_set_maxpsz(queue_t * q,conn_t * connp,size_t size)1000f1702c5SYu Xiangning proto_set_maxpsz(queue_t *q, conn_t *connp, size_t size)
1010f1702c5SYu Xiangning {
1020f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) {
1030f1702c5SYu Xiangning struct sock_proto_props sopp;
1040f1702c5SYu Xiangning
1050f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_MAXPSZ;
1060f1702c5SYu Xiangning sopp.sopp_maxpsz = size;
1070f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props)
1080f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp);
1090f1702c5SYu Xiangning return (B_TRUE);
1100f1702c5SYu Xiangning } else {
1110f1702c5SYu Xiangning struct stdata *stp;
1120f1702c5SYu Xiangning queue_t *wq;
1130f1702c5SYu Xiangning stp = STREAM(q);
1140f1702c5SYu Xiangning
1150f1702c5SYu Xiangning /*
1160f1702c5SYu Xiangning * At this point change of a queue parameter is not allowed
1170f1702c5SYu Xiangning * when a multiplexor is sitting on top.
1180f1702c5SYu Xiangning */
1190f1702c5SYu Xiangning if (stp == NULL || stp->sd_flag & STPLEX)
1200f1702c5SYu Xiangning return (B_FALSE);
1210f1702c5SYu Xiangning
1220f1702c5SYu Xiangning claimstr(stp->sd_wrq);
1230f1702c5SYu Xiangning wq = stp->sd_wrq->q_next;
1240f1702c5SYu Xiangning ASSERT(wq != NULL);
1250f1702c5SYu Xiangning (void) strqset(wq, QMAXPSZ, 0, size);
1260f1702c5SYu Xiangning releasestr(stp->sd_wrq);
1270f1702c5SYu Xiangning return (B_TRUE);
1280f1702c5SYu Xiangning }
1290f1702c5SYu Xiangning }
1300f1702c5SYu Xiangning
1310f1702c5SYu Xiangning /* ARGSUSED */
1320f1702c5SYu Xiangning boolean_t
proto_set_tx_maxblk(queue_t * q,conn_t * connp,ssize_t size)1330f1702c5SYu Xiangning proto_set_tx_maxblk(queue_t *q, conn_t *connp, ssize_t size)
1340f1702c5SYu Xiangning {
1350f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) {
1360f1702c5SYu Xiangning struct sock_proto_props sopp;
1370f1702c5SYu Xiangning
1380f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_MAXBLK;
1390f1702c5SYu Xiangning sopp.sopp_maxblk = size;
1400f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props)
1410f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp);
1420f1702c5SYu Xiangning } else {
1430f1702c5SYu Xiangning MBLKP mp;
1440f1702c5SYu Xiangning struct stroptions *stropt;
1450f1702c5SYu Xiangning
1460f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
1470f1702c5SYu Xiangning return (B_FALSE);
1480f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS;
1490f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt);
1500f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr;
1510f1702c5SYu Xiangning stropt->so_flags = SO_MAXBLK;
1520f1702c5SYu Xiangning stropt->so_maxblk = size;
1530f1702c5SYu Xiangning putnext(q, mp);
1540f1702c5SYu Xiangning }
1550f1702c5SYu Xiangning return (B_TRUE);
1560f1702c5SYu Xiangning }
1570f1702c5SYu Xiangning
1580f1702c5SYu Xiangning boolean_t
proto_set_tx_copyopt(queue_t * q,conn_t * connp,int copyopt)1590f1702c5SYu Xiangning proto_set_tx_copyopt(queue_t *q, conn_t *connp, int copyopt)
1600f1702c5SYu Xiangning {
1610f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) {
1620f1702c5SYu Xiangning struct sock_proto_props sopp;
1630f1702c5SYu Xiangning
1640f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_ZCOPY;
1650f1702c5SYu Xiangning sopp.sopp_zcopyflag = (ushort_t)copyopt;
1660f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props)
1670f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp);
1680f1702c5SYu Xiangning } else {
1690f1702c5SYu Xiangning MBLKP mp;
1700f1702c5SYu Xiangning struct stroptions *stropt;
1710f1702c5SYu Xiangning
1720f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
1730f1702c5SYu Xiangning return (B_FALSE);
1740f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS;
1750f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt);
1760f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr;
1770f1702c5SYu Xiangning stropt->so_flags = SO_COPYOPT;
1780f1702c5SYu Xiangning stropt->so_copyopt = (ushort_t)copyopt;
1790f1702c5SYu Xiangning putnext(q, mp);
1800f1702c5SYu Xiangning }
1810f1702c5SYu Xiangning return (B_TRUE);
1820f1702c5SYu Xiangning }
1830f1702c5SYu Xiangning
1840f1702c5SYu Xiangning boolean_t
proto_set_tx_wroff(queue_t * q,conn_t * connp,size_t size)1850f1702c5SYu Xiangning proto_set_tx_wroff(queue_t *q, conn_t *connp, size_t size)
1860f1702c5SYu Xiangning {
1870f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) {
1880f1702c5SYu Xiangning struct sock_proto_props sopp;
1890f1702c5SYu Xiangning
1900f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_WROFF;
1910f1702c5SYu Xiangning sopp.sopp_wroff = size;
1920f1702c5SYu Xiangning
1930f1702c5SYu Xiangning /* XXX workaround for CR6757374 */
1940f1702c5SYu Xiangning if (connp->conn_upper_handle != NULL)
1950f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props)
1960f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp);
1970f1702c5SYu Xiangning } else {
1980f1702c5SYu Xiangning
1990f1702c5SYu Xiangning MBLKP mp;
2000f1702c5SYu Xiangning struct stroptions *stropt;
2010f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
2020f1702c5SYu Xiangning return (B_FALSE);
2030f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS;
2040f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt);
2050f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr;
2060f1702c5SYu Xiangning stropt->so_flags = SO_WROFF;
2070f1702c5SYu Xiangning stropt->so_wroff = (ushort_t)size;
2080f1702c5SYu Xiangning putnext(q, mp);
2090f1702c5SYu Xiangning }
2100f1702c5SYu Xiangning return (B_TRUE);
2110f1702c5SYu Xiangning }
2120f1702c5SYu Xiangning
2130f1702c5SYu Xiangning /*
2140f1702c5SYu Xiangning * set OOBINLINE processing on the socket
2150f1702c5SYu Xiangning */
2160f1702c5SYu Xiangning void
proto_set_rx_oob_opt(conn_t * connp,boolean_t onoff)2170f1702c5SYu Xiangning proto_set_rx_oob_opt(conn_t *connp, boolean_t onoff)
2180f1702c5SYu Xiangning {
2190f1702c5SYu Xiangning struct sock_proto_props sopp;
2200f1702c5SYu Xiangning
2210f1702c5SYu Xiangning ASSERT(IPCL_IS_NONSTR(connp));
2220f1702c5SYu Xiangning
2230f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_OOBINLINE;
2240f1702c5SYu Xiangning sopp.sopp_oobinline = onoff;
2250f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props)
2260f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp);
2270f1702c5SYu Xiangning }
2280f1702c5SYu Xiangning
2290f1702c5SYu Xiangning /*
2300f1702c5SYu Xiangning * Translate a TLI(/XTI) error into a system error as best we can.
2310f1702c5SYu Xiangning */
2320f1702c5SYu Xiangning static const int tli_errs[] = {
2330f1702c5SYu Xiangning 0, /* no error */
2340f1702c5SYu Xiangning EADDRNOTAVAIL, /* TBADADDR */
2350f1702c5SYu Xiangning ENOPROTOOPT, /* TBADOPT */
2360f1702c5SYu Xiangning EACCES, /* TACCES */
2370f1702c5SYu Xiangning EBADF, /* TBADF */
2380f1702c5SYu Xiangning EADDRNOTAVAIL, /* TNOADDR */
2390f1702c5SYu Xiangning EPROTO, /* TOUTSTATE */
2400f1702c5SYu Xiangning ECONNABORTED, /* TBADSEQ */
2410f1702c5SYu Xiangning 0, /* TSYSERR - will never get */
2420f1702c5SYu Xiangning EPROTO, /* TLOOK - should never be sent by transport */
2430f1702c5SYu Xiangning EMSGSIZE, /* TBADDATA */
2440f1702c5SYu Xiangning EMSGSIZE, /* TBUFOVFLW */
2450f1702c5SYu Xiangning EPROTO, /* TFLOW */
2460f1702c5SYu Xiangning EWOULDBLOCK, /* TNODATA */
2470f1702c5SYu Xiangning EPROTO, /* TNODIS */
2480f1702c5SYu Xiangning EPROTO, /* TNOUDERR */
2490f1702c5SYu Xiangning EINVAL, /* TBADFLAG */
2500f1702c5SYu Xiangning EPROTO, /* TNOREL */
2510f1702c5SYu Xiangning EOPNOTSUPP, /* TNOTSUPPORT */
2520f1702c5SYu Xiangning EPROTO, /* TSTATECHNG */
2530f1702c5SYu Xiangning /* following represent error namespace expansion with XTI */
2540f1702c5SYu Xiangning EPROTO, /* TNOSTRUCTYPE - never sent by transport */
2550f1702c5SYu Xiangning EPROTO, /* TBADNAME - never sent by transport */
2560f1702c5SYu Xiangning EPROTO, /* TBADQLEN - never sent by transport */
2570f1702c5SYu Xiangning EADDRINUSE, /* TADDRBUSY */
2580f1702c5SYu Xiangning EBADF, /* TINDOUT */
2590f1702c5SYu Xiangning EBADF, /* TPROVMISMATCH */
2600f1702c5SYu Xiangning EBADF, /* TRESQLEN */
2610f1702c5SYu Xiangning EBADF, /* TRESADDR */
2620f1702c5SYu Xiangning EPROTO, /* TQFULL - never sent by transport */
2630f1702c5SYu Xiangning EPROTO, /* TPROTO */
2640f1702c5SYu Xiangning };
2650f1702c5SYu Xiangning
2660f1702c5SYu Xiangning int
proto_tlitosyserr(int terr)2670f1702c5SYu Xiangning proto_tlitosyserr(int terr)
2680f1702c5SYu Xiangning {
2690f1702c5SYu Xiangning ASSERT(terr != TSYSERR);
2700f1702c5SYu Xiangning if (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0])))
2710f1702c5SYu Xiangning return (EPROTO);
2720f1702c5SYu Xiangning else
2730f1702c5SYu Xiangning return (tli_errs[terr]);
2740f1702c5SYu Xiangning }
2750f1702c5SYu Xiangning
2760f1702c5SYu Xiangning /*
2770f1702c5SYu Xiangning * Verify that address is suitable for connect/sendmsg and is aligned properly
2780f1702c5SYu Xiangning * Since this is a generic function we do not test for port being zero
2790f1702c5SYu Xiangning * as some protocols like icmp do not require a port
2800f1702c5SYu Xiangning */
2810f1702c5SYu Xiangning int
proto_verify_ip_addr(int family,const struct sockaddr * name,socklen_t namelen)2820f1702c5SYu Xiangning proto_verify_ip_addr(int family, const struct sockaddr *name, socklen_t namelen)
2830f1702c5SYu Xiangning {
2840f1702c5SYu Xiangning
2850f1702c5SYu Xiangning if (name == NULL || !OK_32PTR((char *)name))
2860f1702c5SYu Xiangning return (EINVAL);
2870f1702c5SYu Xiangning
2880f1702c5SYu Xiangning switch (family) {
2890f1702c5SYu Xiangning case AF_INET:
2900f1702c5SYu Xiangning if (name->sa_family != AF_INET) {
2910f1702c5SYu Xiangning return (EAFNOSUPPORT);
2920f1702c5SYu Xiangning }
2930f1702c5SYu Xiangning
2940f1702c5SYu Xiangning if (namelen != (socklen_t)sizeof (struct sockaddr_in)) {
2950f1702c5SYu Xiangning return (EINVAL);
2960f1702c5SYu Xiangning }
2970f1702c5SYu Xiangning break;
2980f1702c5SYu Xiangning case AF_INET6: {
2990f1702c5SYu Xiangning #ifdef DEBUG
3000f1702c5SYu Xiangning struct sockaddr_in6 *sin6;
3010f1702c5SYu Xiangning #endif /* DEBUG */
3020f1702c5SYu Xiangning
3030f1702c5SYu Xiangning if (name->sa_family != AF_INET6) {
3040f1702c5SYu Xiangning return (EAFNOSUPPORT);
3050f1702c5SYu Xiangning }
3060f1702c5SYu Xiangning if (namelen != (socklen_t)sizeof (struct sockaddr_in6)) {
3070f1702c5SYu Xiangning return (EINVAL);
3080f1702c5SYu Xiangning }
3090f1702c5SYu Xiangning #ifdef DEBUG
3100f1702c5SYu Xiangning /* Verify that apps don't forget to clear sin6_scope_id etc */
3110f1702c5SYu Xiangning sin6 = (struct sockaddr_in6 *)name;
3120f1702c5SYu Xiangning if (sin6->sin6_scope_id != 0 &&
3130f1702c5SYu Xiangning !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) {
3140f1702c5SYu Xiangning zcmn_err(getzoneid(), CE_WARN,
3150f1702c5SYu Xiangning "connect/send* with uninitialized sin6_scope_id "
3160f1702c5SYu Xiangning "(%d) on socket. Pid = %d\n",
3170f1702c5SYu Xiangning (int)sin6->sin6_scope_id, (int)curproc->p_pid);
3180f1702c5SYu Xiangning }
3190f1702c5SYu Xiangning #endif /* DEBUG */
3200f1702c5SYu Xiangning break;
3210f1702c5SYu Xiangning }
3220f1702c5SYu Xiangning default:
3230f1702c5SYu Xiangning return (EINVAL);
3240f1702c5SYu Xiangning }
3250f1702c5SYu Xiangning
3260f1702c5SYu Xiangning return (0);
3270f1702c5SYu Xiangning }
3280f1702c5SYu Xiangning
3290f1702c5SYu Xiangning /*
3300f1702c5SYu Xiangning * Do a lookup of the options in the array.
3310f1702c5SYu Xiangning * Rerurn NULL if there isn't a match.
3320f1702c5SYu Xiangning */
3330f1702c5SYu Xiangning opdes_t *
proto_opt_lookup(t_uscalar_t level,t_uscalar_t name,opdes_t * opt_arr,uint_t opt_arr_cnt)3340f1702c5SYu Xiangning proto_opt_lookup(t_uscalar_t level, t_uscalar_t name, opdes_t *opt_arr,
3350f1702c5SYu Xiangning uint_t opt_arr_cnt)
3360f1702c5SYu Xiangning {
3370f1702c5SYu Xiangning opdes_t *optd;
3380f1702c5SYu Xiangning
3390f1702c5SYu Xiangning for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt];
3400f1702c5SYu Xiangning optd++) {
3410f1702c5SYu Xiangning if (level == (uint_t)optd->opdes_level &&
3420f1702c5SYu Xiangning name == (uint_t)optd->opdes_name)
3430f1702c5SYu Xiangning return (optd);
3440f1702c5SYu Xiangning }
3450f1702c5SYu Xiangning return (NULL);
3460f1702c5SYu Xiangning }
3470f1702c5SYu Xiangning
3480f1702c5SYu Xiangning /*
3490f1702c5SYu Xiangning * Do a lookup of the options in the array and do permission and length checking
3500f1702c5SYu Xiangning * Returns zero if there is no error (note: for non-tpi-providers not being able
351*bd670b35SErik Nordmark * to find the option is not an error). TPI errors are returned as negative
352*bd670b35SErik Nordmark * numbers and errnos as positive numbers.
353*bd670b35SErik Nordmark * If max_len is set we update it based on the max length of the option.
3540f1702c5SYu Xiangning */
3550f1702c5SYu Xiangning int
proto_opt_check(int level,int name,int len,t_uscalar_t * max_len,opdes_t * opt_arr,uint_t opt_arr_cnt,boolean_t negotiate,boolean_t check,cred_t * cr)3560f1702c5SYu Xiangning proto_opt_check(int level, int name, int len, t_uscalar_t *max_len,
357*bd670b35SErik Nordmark opdes_t *opt_arr, uint_t opt_arr_cnt, boolean_t negotiate, boolean_t check,
358*bd670b35SErik Nordmark cred_t *cr)
3590f1702c5SYu Xiangning {
3600f1702c5SYu Xiangning opdes_t *optd;
3610f1702c5SYu Xiangning
3620f1702c5SYu Xiangning /* Find the option in the opt_arr. */
363*bd670b35SErik Nordmark optd = proto_opt_lookup(level, name, opt_arr, opt_arr_cnt);
364*bd670b35SErik Nordmark if (optd == NULL)
3650f1702c5SYu Xiangning return (-TBADOPT);
3660f1702c5SYu Xiangning
3670f1702c5SYu Xiangning /* Additional checks dependent on operation. */
3680f1702c5SYu Xiangning if (negotiate) {
3690f1702c5SYu Xiangning /* Cannot be true at the same time */
3700f1702c5SYu Xiangning ASSERT(check == B_FALSE);
3710f1702c5SYu Xiangning
3720f1702c5SYu Xiangning if (!OA_WRITE_OR_EXECUTE(optd, cr)) {
3730f1702c5SYu Xiangning /* can't negotiate option */
3740f1702c5SYu Xiangning if (!(OA_MATCHED_PRIV(optd, cr)) &&
3750f1702c5SYu Xiangning OA_WX_ANYPRIV(optd)) {
3760f1702c5SYu Xiangning /*
3770f1702c5SYu Xiangning * not privileged but privilege
3780f1702c5SYu Xiangning * will help negotiate option.
3790f1702c5SYu Xiangning */
3800f1702c5SYu Xiangning return (-TACCES);
3810f1702c5SYu Xiangning } else {
3820f1702c5SYu Xiangning return (-TBADOPT);
3830f1702c5SYu Xiangning }
3840f1702c5SYu Xiangning }
3850f1702c5SYu Xiangning /*
3860f1702c5SYu Xiangning * Verify size for options
3870f1702c5SYu Xiangning * Note: For retaining compatibility with historical
3880f1702c5SYu Xiangning * behavior, variable lengths options will have their
3890f1702c5SYu Xiangning * length verified in the setfn() processing.
3900f1702c5SYu Xiangning * In order to be compatible with SunOS 4.X we return
3910f1702c5SYu Xiangning * EINVAL errors for bad lengths.
3920f1702c5SYu Xiangning */
3930f1702c5SYu Xiangning if (!(optd->opdes_props & OP_VARLEN)) {
3940f1702c5SYu Xiangning /* fixed length - size must match */
3950f1702c5SYu Xiangning if (len != optd->opdes_size) {
3960f1702c5SYu Xiangning return (EINVAL);
3970f1702c5SYu Xiangning }
3980f1702c5SYu Xiangning }
3990f1702c5SYu Xiangning } else {
4000f1702c5SYu Xiangning if (check) {
4010f1702c5SYu Xiangning if (!OA_RWX_ANYPRIV(optd))
4020f1702c5SYu Xiangning /* any of "rwx" permission but not none */
4030f1702c5SYu Xiangning return (-TBADOPT);
4040f1702c5SYu Xiangning }
4050f1702c5SYu Xiangning /*
4060f1702c5SYu Xiangning * XXX Since T_CURRENT was not there in TLI and the
4070f1702c5SYu Xiangning * official TLI inspired TPI standard, getsockopt()
4080f1702c5SYu Xiangning * API uses T_CHECK (for T_CURRENT semantics)
409*bd670b35SErik Nordmark * Thus T_CHECK includes the T_CURRENT semantics due to that
410*bd670b35SErik Nordmark * historical use.
4110f1702c5SYu Xiangning */
4120f1702c5SYu Xiangning if (!OA_READ_PERMISSION(optd, cr)) {
4130f1702c5SYu Xiangning /* can't read option value */
4140f1702c5SYu Xiangning if (!(OA_MATCHED_PRIV(optd, cr)) &&
4150f1702c5SYu Xiangning OA_R_ANYPRIV(optd)) {
4160f1702c5SYu Xiangning /*
4170f1702c5SYu Xiangning * not privileged but privilege
4180f1702c5SYu Xiangning * will help in reading option value.
4190f1702c5SYu Xiangning */
4200f1702c5SYu Xiangning return (-TACCES);
4210f1702c5SYu Xiangning } else {
4220f1702c5SYu Xiangning return (-TBADOPT);
4230f1702c5SYu Xiangning }
4240f1702c5SYu Xiangning }
4250f1702c5SYu Xiangning }
4260f1702c5SYu Xiangning if (max_len != NULL)
4270f1702c5SYu Xiangning *max_len = optd->opdes_size;
4280f1702c5SYu Xiangning
4290f1702c5SYu Xiangning /* We liked it. Keep going. */
4300f1702c5SYu Xiangning return (0);
4310f1702c5SYu Xiangning }
432