xref: /illumos-gate/usr/src/uts/common/inet/proto_set.c (revision bd670b35)
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)
365*bd670b35SErik Nordmark 		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