xref: /onnv-gate/usr/src/uts/common/inet/proto_set.c (revision 11042:2d6e217af1b4)
18348SEric.Yu@Sun.COM /*
28348SEric.Yu@Sun.COM  * CDDL HEADER START
38348SEric.Yu@Sun.COM  *
48348SEric.Yu@Sun.COM  * The contents of this file are subject to the terms of the
58348SEric.Yu@Sun.COM  * Common Development and Distribution License (the "License").
68348SEric.Yu@Sun.COM  * You may not use this file except in compliance with the License.
78348SEric.Yu@Sun.COM  *
88348SEric.Yu@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98348SEric.Yu@Sun.COM  * or http://www.opensolaris.org/os/licensing.
108348SEric.Yu@Sun.COM  * See the License for the specific language governing permissions
118348SEric.Yu@Sun.COM  * and limitations under the License.
128348SEric.Yu@Sun.COM  *
138348SEric.Yu@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
148348SEric.Yu@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158348SEric.Yu@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
168348SEric.Yu@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
178348SEric.Yu@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
188348SEric.Yu@Sun.COM  *
198348SEric.Yu@Sun.COM  * CDDL HEADER END
208348SEric.Yu@Sun.COM  */
218348SEric.Yu@Sun.COM /*
22*11042SErik.Nordmark@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
238348SEric.Yu@Sun.COM  * Use is subject to license terms.
248348SEric.Yu@Sun.COM  */
258348SEric.Yu@Sun.COM 
268348SEric.Yu@Sun.COM #include <sys/types.h>
278348SEric.Yu@Sun.COM #include <inet/common.h>
288348SEric.Yu@Sun.COM #include <sys/stream.h>
298348SEric.Yu@Sun.COM #include <sys/stropts.h>
308348SEric.Yu@Sun.COM #include <sys/strsun.h>
318348SEric.Yu@Sun.COM #include <sys/sysmacros.h>
328348SEric.Yu@Sun.COM #include <sys/stropts.h>
338348SEric.Yu@Sun.COM #include <sys/strsubr.h>
348348SEric.Yu@Sun.COM #include <sys/tpicommon.h>
358348SEric.Yu@Sun.COM #include <sys/socket_proto.h>
368348SEric.Yu@Sun.COM #include <sys/policy.h>
378348SEric.Yu@Sun.COM #include <inet/optcom.h>
388348SEric.Yu@Sun.COM #include <inet/ipclassifier.h>
398348SEric.Yu@Sun.COM 
408348SEric.Yu@Sun.COM boolean_t
proto_set_rx_hiwat(queue_t * q,conn_t * connp,size_t size)418348SEric.Yu@Sun.COM proto_set_rx_hiwat(queue_t *q, conn_t *connp, size_t size)
428348SEric.Yu@Sun.COM {
438348SEric.Yu@Sun.COM 
448348SEric.Yu@Sun.COM 	if (connp != NULL && IPCL_IS_NONSTR(connp)) {
458348SEric.Yu@Sun.COM 		struct sock_proto_props sopp;
468348SEric.Yu@Sun.COM 
478348SEric.Yu@Sun.COM 		sopp.sopp_flags = SOCKOPT_RCVHIWAT;
488348SEric.Yu@Sun.COM 		sopp.sopp_rxhiwat = size;
498348SEric.Yu@Sun.COM 		(*connp->conn_upcalls->su_set_proto_props)
508348SEric.Yu@Sun.COM 		    (connp->conn_upper_handle, &sopp);
518348SEric.Yu@Sun.COM 	} else {
528348SEric.Yu@Sun.COM 		MBLKP	mp;
538348SEric.Yu@Sun.COM 		struct stroptions *stropt;
548348SEric.Yu@Sun.COM 
558348SEric.Yu@Sun.COM 		if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
568348SEric.Yu@Sun.COM 			return (B_FALSE);
578348SEric.Yu@Sun.COM 		mp->b_datap->db_type = M_SETOPTS;
588348SEric.Yu@Sun.COM 		mp->b_wptr += sizeof (*stropt);
598348SEric.Yu@Sun.COM 		stropt = (struct stroptions *)mp->b_rptr;
608348SEric.Yu@Sun.COM 		stropt->so_flags = SO_HIWAT;
618348SEric.Yu@Sun.COM 		stropt->so_hiwat = size;
628348SEric.Yu@Sun.COM 		putnext(q, mp);
638348SEric.Yu@Sun.COM 	}
648348SEric.Yu@Sun.COM 	return (B_TRUE);
658348SEric.Yu@Sun.COM }
668348SEric.Yu@Sun.COM 
678348SEric.Yu@Sun.COM boolean_t
proto_set_rx_lowat(queue_t * q,conn_t * connp,size_t size)688348SEric.Yu@Sun.COM proto_set_rx_lowat(queue_t *q, conn_t *connp, size_t size)
698348SEric.Yu@Sun.COM {
708348SEric.Yu@Sun.COM 
718348SEric.Yu@Sun.COM 	if (connp != NULL && IPCL_IS_NONSTR(connp)) {
728348SEric.Yu@Sun.COM 		struct sock_proto_props sopp;
738348SEric.Yu@Sun.COM 
748348SEric.Yu@Sun.COM 		sopp.sopp_flags = SOCKOPT_RCVLOWAT;
758348SEric.Yu@Sun.COM 		sopp.sopp_rxlowat = size;
768348SEric.Yu@Sun.COM 		(*connp->conn_upcalls->su_set_proto_props)
778348SEric.Yu@Sun.COM 		    (connp->conn_upper_handle, &sopp);
788348SEric.Yu@Sun.COM 	} else {
798348SEric.Yu@Sun.COM 		MBLKP	mp;
808348SEric.Yu@Sun.COM 		struct stroptions *stropt;
818348SEric.Yu@Sun.COM 
828348SEric.Yu@Sun.COM 		if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
838348SEric.Yu@Sun.COM 			return (B_FALSE);
848348SEric.Yu@Sun.COM 		mp->b_datap->db_type = M_SETOPTS;
858348SEric.Yu@Sun.COM 		mp->b_wptr += sizeof (*stropt);
868348SEric.Yu@Sun.COM 		stropt = (struct stroptions *)mp->b_rptr;
878348SEric.Yu@Sun.COM 		stropt->so_flags = SO_LOWAT;
888348SEric.Yu@Sun.COM 		stropt->so_lowat = size;
898348SEric.Yu@Sun.COM 		putnext(q, mp);
908348SEric.Yu@Sun.COM 	}
918348SEric.Yu@Sun.COM 	return (B_TRUE);
928348SEric.Yu@Sun.COM }
938348SEric.Yu@Sun.COM 
948348SEric.Yu@Sun.COM /*
958348SEric.Yu@Sun.COM  * Set maximum packet size. This is the maximum amount of data the protocol
968348SEric.Yu@Sun.COM  * wants to be given at any time, Larger data needs to be broken in multiples
978348SEric.Yu@Sun.COM  * of maximum packet size and given to the protocol one at a time.
988348SEric.Yu@Sun.COM  */
998348SEric.Yu@Sun.COM boolean_t
proto_set_maxpsz(queue_t * q,conn_t * connp,size_t size)1008348SEric.Yu@Sun.COM proto_set_maxpsz(queue_t *q, conn_t *connp, size_t size)
1018348SEric.Yu@Sun.COM {
1028348SEric.Yu@Sun.COM 	if (connp != NULL && IPCL_IS_NONSTR(connp)) {
1038348SEric.Yu@Sun.COM 		struct sock_proto_props sopp;
1048348SEric.Yu@Sun.COM 
1058348SEric.Yu@Sun.COM 		sopp.sopp_flags = SOCKOPT_MAXPSZ;
1068348SEric.Yu@Sun.COM 		sopp.sopp_maxpsz = size;
1078348SEric.Yu@Sun.COM 		(*connp->conn_upcalls->su_set_proto_props)
1088348SEric.Yu@Sun.COM 		    (connp->conn_upper_handle, &sopp);
1098348SEric.Yu@Sun.COM 		return (B_TRUE);
1108348SEric.Yu@Sun.COM 	} else {
1118348SEric.Yu@Sun.COM 		struct stdata	*stp;
1128348SEric.Yu@Sun.COM 		queue_t		*wq;
1138348SEric.Yu@Sun.COM 		stp = STREAM(q);
1148348SEric.Yu@Sun.COM 
1158348SEric.Yu@Sun.COM 		/*
1168348SEric.Yu@Sun.COM 		 * At this point change of a queue parameter is not allowed
1178348SEric.Yu@Sun.COM 		 * when a multiplexor is sitting on top.
1188348SEric.Yu@Sun.COM 		 */
1198348SEric.Yu@Sun.COM 		if (stp == NULL || stp->sd_flag & STPLEX)
1208348SEric.Yu@Sun.COM 			return (B_FALSE);
1218348SEric.Yu@Sun.COM 
1228348SEric.Yu@Sun.COM 		claimstr(stp->sd_wrq);
1238348SEric.Yu@Sun.COM 		wq = stp->sd_wrq->q_next;
1248348SEric.Yu@Sun.COM 		ASSERT(wq != NULL);
1258348SEric.Yu@Sun.COM 		(void) strqset(wq, QMAXPSZ, 0, size);
1268348SEric.Yu@Sun.COM 		releasestr(stp->sd_wrq);
1278348SEric.Yu@Sun.COM 		return (B_TRUE);
1288348SEric.Yu@Sun.COM 	}
1298348SEric.Yu@Sun.COM }
1308348SEric.Yu@Sun.COM 
1318348SEric.Yu@Sun.COM /* ARGSUSED */
1328348SEric.Yu@Sun.COM boolean_t
proto_set_tx_maxblk(queue_t * q,conn_t * connp,ssize_t size)1338348SEric.Yu@Sun.COM proto_set_tx_maxblk(queue_t *q, conn_t *connp, ssize_t size)
1348348SEric.Yu@Sun.COM {
1358348SEric.Yu@Sun.COM 	if (connp != NULL && IPCL_IS_NONSTR(connp)) {
1368348SEric.Yu@Sun.COM 		struct sock_proto_props sopp;
1378348SEric.Yu@Sun.COM 
1388348SEric.Yu@Sun.COM 		sopp.sopp_flags = SOCKOPT_MAXBLK;
1398348SEric.Yu@Sun.COM 		sopp.sopp_maxblk = size;
1408348SEric.Yu@Sun.COM 		(*connp->conn_upcalls->su_set_proto_props)
1418348SEric.Yu@Sun.COM 		    (connp->conn_upper_handle, &sopp);
1428348SEric.Yu@Sun.COM 	} else {
1438348SEric.Yu@Sun.COM 		MBLKP	mp;
1448348SEric.Yu@Sun.COM 		struct stroptions *stropt;
1458348SEric.Yu@Sun.COM 
1468348SEric.Yu@Sun.COM 		if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
1478348SEric.Yu@Sun.COM 			return (B_FALSE);
1488348SEric.Yu@Sun.COM 		mp->b_datap->db_type = M_SETOPTS;
1498348SEric.Yu@Sun.COM 		mp->b_wptr += sizeof (*stropt);
1508348SEric.Yu@Sun.COM 		stropt = (struct stroptions *)mp->b_rptr;
1518348SEric.Yu@Sun.COM 		stropt->so_flags = SO_MAXBLK;
1528348SEric.Yu@Sun.COM 		stropt->so_maxblk = size;
1538348SEric.Yu@Sun.COM 		putnext(q, mp);
1548348SEric.Yu@Sun.COM 	}
1558348SEric.Yu@Sun.COM 	return (B_TRUE);
1568348SEric.Yu@Sun.COM }
1578348SEric.Yu@Sun.COM 
1588348SEric.Yu@Sun.COM boolean_t
proto_set_tx_copyopt(queue_t * q,conn_t * connp,int copyopt)1598348SEric.Yu@Sun.COM proto_set_tx_copyopt(queue_t *q, conn_t *connp, int copyopt)
1608348SEric.Yu@Sun.COM {
1618348SEric.Yu@Sun.COM 	if (connp != NULL && IPCL_IS_NONSTR(connp)) {
1628348SEric.Yu@Sun.COM 		struct sock_proto_props sopp;
1638348SEric.Yu@Sun.COM 
1648348SEric.Yu@Sun.COM 		sopp.sopp_flags = SOCKOPT_ZCOPY;
1658348SEric.Yu@Sun.COM 		sopp.sopp_zcopyflag = (ushort_t)copyopt;
1668348SEric.Yu@Sun.COM 		(*connp->conn_upcalls->su_set_proto_props)
1678348SEric.Yu@Sun.COM 		    (connp->conn_upper_handle, &sopp);
1688348SEric.Yu@Sun.COM 	} else {
1698348SEric.Yu@Sun.COM 		MBLKP	mp;
1708348SEric.Yu@Sun.COM 		struct stroptions *stropt;
1718348SEric.Yu@Sun.COM 
1728348SEric.Yu@Sun.COM 		if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
1738348SEric.Yu@Sun.COM 			return (B_FALSE);
1748348SEric.Yu@Sun.COM 		mp->b_datap->db_type = M_SETOPTS;
1758348SEric.Yu@Sun.COM 		mp->b_wptr += sizeof (*stropt);
1768348SEric.Yu@Sun.COM 		stropt = (struct stroptions *)mp->b_rptr;
1778348SEric.Yu@Sun.COM 		stropt->so_flags = SO_COPYOPT;
1788348SEric.Yu@Sun.COM 		stropt->so_copyopt = (ushort_t)copyopt;
1798348SEric.Yu@Sun.COM 		putnext(q, mp);
1808348SEric.Yu@Sun.COM 	}
1818348SEric.Yu@Sun.COM 	return (B_TRUE);
1828348SEric.Yu@Sun.COM }
1838348SEric.Yu@Sun.COM 
1848348SEric.Yu@Sun.COM boolean_t
proto_set_tx_wroff(queue_t * q,conn_t * connp,size_t size)1858348SEric.Yu@Sun.COM proto_set_tx_wroff(queue_t *q, conn_t *connp, size_t size)
1868348SEric.Yu@Sun.COM {
1878348SEric.Yu@Sun.COM 	if (connp != NULL && IPCL_IS_NONSTR(connp)) {
1888348SEric.Yu@Sun.COM 		struct sock_proto_props sopp;
1898348SEric.Yu@Sun.COM 
1908348SEric.Yu@Sun.COM 		sopp.sopp_flags = SOCKOPT_WROFF;
1918348SEric.Yu@Sun.COM 		sopp.sopp_wroff = size;
1928348SEric.Yu@Sun.COM 
1938348SEric.Yu@Sun.COM 		/* XXX workaround for CR6757374 */
1948348SEric.Yu@Sun.COM 		if (connp->conn_upper_handle != NULL)
1958348SEric.Yu@Sun.COM 			(*connp->conn_upcalls->su_set_proto_props)
1968348SEric.Yu@Sun.COM 			    (connp->conn_upper_handle, &sopp);
1978348SEric.Yu@Sun.COM 	} else {
1988348SEric.Yu@Sun.COM 
1998348SEric.Yu@Sun.COM 		MBLKP	mp;
2008348SEric.Yu@Sun.COM 		struct stroptions *stropt;
2018348SEric.Yu@Sun.COM 		if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
2028348SEric.Yu@Sun.COM 			return (B_FALSE);
2038348SEric.Yu@Sun.COM 		mp->b_datap->db_type = M_SETOPTS;
2048348SEric.Yu@Sun.COM 		mp->b_wptr += sizeof (*stropt);
2058348SEric.Yu@Sun.COM 		stropt = (struct stroptions *)mp->b_rptr;
2068348SEric.Yu@Sun.COM 		stropt->so_flags = SO_WROFF;
2078348SEric.Yu@Sun.COM 		stropt->so_wroff = (ushort_t)size;
2088348SEric.Yu@Sun.COM 		putnext(q, mp);
2098348SEric.Yu@Sun.COM 	}
2108348SEric.Yu@Sun.COM 	return (B_TRUE);
2118348SEric.Yu@Sun.COM }
2128348SEric.Yu@Sun.COM 
2138348SEric.Yu@Sun.COM /*
2148348SEric.Yu@Sun.COM  * set OOBINLINE processing on the socket
2158348SEric.Yu@Sun.COM  */
2168348SEric.Yu@Sun.COM void
proto_set_rx_oob_opt(conn_t * connp,boolean_t onoff)2178348SEric.Yu@Sun.COM proto_set_rx_oob_opt(conn_t *connp, boolean_t onoff)
2188348SEric.Yu@Sun.COM {
2198348SEric.Yu@Sun.COM 	struct sock_proto_props sopp;
2208348SEric.Yu@Sun.COM 
2218348SEric.Yu@Sun.COM 	ASSERT(IPCL_IS_NONSTR(connp));
2228348SEric.Yu@Sun.COM 
2238348SEric.Yu@Sun.COM 	sopp.sopp_flags = SOCKOPT_OOBINLINE;
2248348SEric.Yu@Sun.COM 	sopp.sopp_oobinline = onoff;
2258348SEric.Yu@Sun.COM 	(*connp->conn_upcalls->su_set_proto_props)
2268348SEric.Yu@Sun.COM 	    (connp->conn_upper_handle, &sopp);
2278348SEric.Yu@Sun.COM }
2288348SEric.Yu@Sun.COM 
2298348SEric.Yu@Sun.COM /*
2308348SEric.Yu@Sun.COM  * Translate a TLI(/XTI) error into a system error as best we can.
2318348SEric.Yu@Sun.COM  */
2328348SEric.Yu@Sun.COM static const int tli_errs[] = {
2338348SEric.Yu@Sun.COM 		0,		/* no error	*/
2348348SEric.Yu@Sun.COM 		EADDRNOTAVAIL,  /* TBADADDR	*/
2358348SEric.Yu@Sun.COM 		ENOPROTOOPT,	/* TBADOPT	*/
2368348SEric.Yu@Sun.COM 		EACCES,		/* TACCES	*/
2378348SEric.Yu@Sun.COM 		EBADF,		/* TBADF	*/
2388348SEric.Yu@Sun.COM 		EADDRNOTAVAIL,	/* TNOADDR	*/
2398348SEric.Yu@Sun.COM 		EPROTO,		/* TOUTSTATE	*/
2408348SEric.Yu@Sun.COM 		ECONNABORTED,	/* TBADSEQ	*/
2418348SEric.Yu@Sun.COM 		0,		/* TSYSERR - will never get	*/
2428348SEric.Yu@Sun.COM 		EPROTO,		/* TLOOK - should never be sent by transport */
2438348SEric.Yu@Sun.COM 		EMSGSIZE,	/* TBADDATA	*/
2448348SEric.Yu@Sun.COM 		EMSGSIZE,	/* TBUFOVFLW	*/
2458348SEric.Yu@Sun.COM 		EPROTO,		/* TFLOW	*/
2468348SEric.Yu@Sun.COM 		EWOULDBLOCK,	/* TNODATA	*/
2478348SEric.Yu@Sun.COM 		EPROTO,		/* TNODIS	*/
2488348SEric.Yu@Sun.COM 		EPROTO,		/* TNOUDERR	*/
2498348SEric.Yu@Sun.COM 		EINVAL,		/* TBADFLAG	*/
2508348SEric.Yu@Sun.COM 		EPROTO,		/* TNOREL	*/
2518348SEric.Yu@Sun.COM 		EOPNOTSUPP,	/* TNOTSUPPORT	*/
2528348SEric.Yu@Sun.COM 		EPROTO,		/* TSTATECHNG	*/
2538348SEric.Yu@Sun.COM 		/* following represent error namespace expansion with XTI */
2548348SEric.Yu@Sun.COM 		EPROTO,		/* TNOSTRUCTYPE - never sent by transport */
2558348SEric.Yu@Sun.COM 		EPROTO,		/* TBADNAME - never sent by transport */
2568348SEric.Yu@Sun.COM 		EPROTO,		/* TBADQLEN - never sent by transport */
2578348SEric.Yu@Sun.COM 		EADDRINUSE,	/* TADDRBUSY	*/
2588348SEric.Yu@Sun.COM 		EBADF,		/* TINDOUT	*/
2598348SEric.Yu@Sun.COM 		EBADF,		/* TPROVMISMATCH */
2608348SEric.Yu@Sun.COM 		EBADF,		/* TRESQLEN	*/
2618348SEric.Yu@Sun.COM 		EBADF,		/* TRESADDR	*/
2628348SEric.Yu@Sun.COM 		EPROTO,		/* TQFULL - never sent by transport */
2638348SEric.Yu@Sun.COM 		EPROTO,		/* TPROTO	*/
2648348SEric.Yu@Sun.COM };
2658348SEric.Yu@Sun.COM 
2668348SEric.Yu@Sun.COM int
proto_tlitosyserr(int terr)2678348SEric.Yu@Sun.COM proto_tlitosyserr(int terr)
2688348SEric.Yu@Sun.COM {
2698348SEric.Yu@Sun.COM 	ASSERT(terr != TSYSERR);
2708348SEric.Yu@Sun.COM 	if (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0])))
2718348SEric.Yu@Sun.COM 		return (EPROTO);
2728348SEric.Yu@Sun.COM 	else
2738348SEric.Yu@Sun.COM 		return (tli_errs[terr]);
2748348SEric.Yu@Sun.COM }
2758348SEric.Yu@Sun.COM 
2768348SEric.Yu@Sun.COM /*
2778348SEric.Yu@Sun.COM  * Verify that address is suitable for connect/sendmsg and is aligned properly
2788348SEric.Yu@Sun.COM  * Since this is a generic function we do not test for port being zero
2798348SEric.Yu@Sun.COM  * as some protocols like icmp do not require a port
2808348SEric.Yu@Sun.COM  */
2818348SEric.Yu@Sun.COM int
proto_verify_ip_addr(int family,const struct sockaddr * name,socklen_t namelen)2828348SEric.Yu@Sun.COM proto_verify_ip_addr(int family, const struct sockaddr *name, socklen_t namelen)
2838348SEric.Yu@Sun.COM {
2848348SEric.Yu@Sun.COM 
2858348SEric.Yu@Sun.COM 	if (name == NULL || !OK_32PTR((char *)name))
2868348SEric.Yu@Sun.COM 		return (EINVAL);
2878348SEric.Yu@Sun.COM 
2888348SEric.Yu@Sun.COM 	switch (family) {
2898348SEric.Yu@Sun.COM 	case AF_INET:
2908348SEric.Yu@Sun.COM 		if (name->sa_family != AF_INET) {
2918348SEric.Yu@Sun.COM 			return (EAFNOSUPPORT);
2928348SEric.Yu@Sun.COM 		}
2938348SEric.Yu@Sun.COM 
2948348SEric.Yu@Sun.COM 		if (namelen != (socklen_t)sizeof (struct sockaddr_in)) {
2958348SEric.Yu@Sun.COM 			return (EINVAL);
2968348SEric.Yu@Sun.COM 		}
2978348SEric.Yu@Sun.COM 		break;
2988348SEric.Yu@Sun.COM 	case AF_INET6: {
2998348SEric.Yu@Sun.COM #ifdef DEBUG
3008348SEric.Yu@Sun.COM 		struct sockaddr_in6 *sin6;
3018348SEric.Yu@Sun.COM #endif /* DEBUG */
3028348SEric.Yu@Sun.COM 
3038348SEric.Yu@Sun.COM 		if (name->sa_family != AF_INET6) {
3048348SEric.Yu@Sun.COM 			return (EAFNOSUPPORT);
3058348SEric.Yu@Sun.COM 		}
3068348SEric.Yu@Sun.COM 		if (namelen != (socklen_t)sizeof (struct sockaddr_in6)) {
3078348SEric.Yu@Sun.COM 			return (EINVAL);
3088348SEric.Yu@Sun.COM 		}
3098348SEric.Yu@Sun.COM #ifdef DEBUG
3108348SEric.Yu@Sun.COM 		/* Verify that apps don't forget to clear sin6_scope_id etc */
3118348SEric.Yu@Sun.COM 		sin6 = (struct sockaddr_in6 *)name;
3128348SEric.Yu@Sun.COM 		if (sin6->sin6_scope_id != 0 &&
3138348SEric.Yu@Sun.COM 		    !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) {
3148348SEric.Yu@Sun.COM 			zcmn_err(getzoneid(), CE_WARN,
3158348SEric.Yu@Sun.COM 			    "connect/send* with uninitialized sin6_scope_id "
3168348SEric.Yu@Sun.COM 			    "(%d) on socket. Pid = %d\n",
3178348SEric.Yu@Sun.COM 			    (int)sin6->sin6_scope_id, (int)curproc->p_pid);
3188348SEric.Yu@Sun.COM 		}
3198348SEric.Yu@Sun.COM #endif /* DEBUG */
3208348SEric.Yu@Sun.COM 		break;
3218348SEric.Yu@Sun.COM 	}
3228348SEric.Yu@Sun.COM 	default:
3238348SEric.Yu@Sun.COM 		return (EINVAL);
3248348SEric.Yu@Sun.COM 	}
3258348SEric.Yu@Sun.COM 
3268348SEric.Yu@Sun.COM 	return (0);
3278348SEric.Yu@Sun.COM }
3288348SEric.Yu@Sun.COM 
3298348SEric.Yu@Sun.COM /*
3308348SEric.Yu@Sun.COM  * Do a lookup of the options in the array.
3318348SEric.Yu@Sun.COM  * Rerurn NULL if there isn't a match.
3328348SEric.Yu@Sun.COM  */
3338348SEric.Yu@Sun.COM opdes_t *
proto_opt_lookup(t_uscalar_t level,t_uscalar_t name,opdes_t * opt_arr,uint_t opt_arr_cnt)3348348SEric.Yu@Sun.COM proto_opt_lookup(t_uscalar_t level, t_uscalar_t name, opdes_t *opt_arr,
3358348SEric.Yu@Sun.COM     uint_t opt_arr_cnt)
3368348SEric.Yu@Sun.COM {
3378348SEric.Yu@Sun.COM 	opdes_t		*optd;
3388348SEric.Yu@Sun.COM 
3398348SEric.Yu@Sun.COM 	for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt];
3408348SEric.Yu@Sun.COM 	    optd++) {
3418348SEric.Yu@Sun.COM 		if (level == (uint_t)optd->opdes_level &&
3428348SEric.Yu@Sun.COM 		    name == (uint_t)optd->opdes_name)
3438348SEric.Yu@Sun.COM 			return (optd);
3448348SEric.Yu@Sun.COM 	}
3458348SEric.Yu@Sun.COM 	return (NULL);
3468348SEric.Yu@Sun.COM }
3478348SEric.Yu@Sun.COM 
3488348SEric.Yu@Sun.COM /*
3498348SEric.Yu@Sun.COM  * Do a lookup of the options in the array and do permission and length checking
3508348SEric.Yu@Sun.COM  * Returns zero if there is no error (note: for non-tpi-providers not being able
351*11042SErik.Nordmark@Sun.COM  * to find the option is not an error). TPI errors are returned as negative
352*11042SErik.Nordmark@Sun.COM  * numbers and errnos as positive numbers.
353*11042SErik.Nordmark@Sun.COM  * If max_len is set we update it based on the max length of the option.
3548348SEric.Yu@Sun.COM  */
3558348SEric.Yu@Sun.COM 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)3568348SEric.Yu@Sun.COM proto_opt_check(int level, int name, int len, t_uscalar_t *max_len,
357*11042SErik.Nordmark@Sun.COM     opdes_t *opt_arr, uint_t opt_arr_cnt, boolean_t negotiate, boolean_t check,
358*11042SErik.Nordmark@Sun.COM     cred_t *cr)
3598348SEric.Yu@Sun.COM {
3608348SEric.Yu@Sun.COM 	opdes_t *optd;
3618348SEric.Yu@Sun.COM 
3628348SEric.Yu@Sun.COM 	/* Find the option in the opt_arr. */
363*11042SErik.Nordmark@Sun.COM 	optd = proto_opt_lookup(level, name, opt_arr, opt_arr_cnt);
364*11042SErik.Nordmark@Sun.COM 	if (optd == NULL)
365*11042SErik.Nordmark@Sun.COM 		return (-TBADOPT);
3668348SEric.Yu@Sun.COM 
3678348SEric.Yu@Sun.COM 	/* Additional checks dependent on operation. */
3688348SEric.Yu@Sun.COM 	if (negotiate) {
3698348SEric.Yu@Sun.COM 		/* Cannot be true at the same time */
3708348SEric.Yu@Sun.COM 		ASSERT(check == B_FALSE);
3718348SEric.Yu@Sun.COM 
3728348SEric.Yu@Sun.COM 		if (!OA_WRITE_OR_EXECUTE(optd, cr)) {
3738348SEric.Yu@Sun.COM 			/* can't negotiate option */
3748348SEric.Yu@Sun.COM 			if (!(OA_MATCHED_PRIV(optd, cr)) &&
3758348SEric.Yu@Sun.COM 			    OA_WX_ANYPRIV(optd)) {
3768348SEric.Yu@Sun.COM 				/*
3778348SEric.Yu@Sun.COM 				 * not privileged but privilege
3788348SEric.Yu@Sun.COM 				 * will help negotiate option.
3798348SEric.Yu@Sun.COM 				 */
3808348SEric.Yu@Sun.COM 				return (-TACCES);
3818348SEric.Yu@Sun.COM 			} else {
3828348SEric.Yu@Sun.COM 				return (-TBADOPT);
3838348SEric.Yu@Sun.COM 			}
3848348SEric.Yu@Sun.COM 		}
3858348SEric.Yu@Sun.COM 		/*
3868348SEric.Yu@Sun.COM 		 * Verify size for options
3878348SEric.Yu@Sun.COM 		 * Note: For retaining compatibility with historical
3888348SEric.Yu@Sun.COM 		 * behavior, variable lengths options will have their
3898348SEric.Yu@Sun.COM 		 * length verified in the setfn() processing.
3908348SEric.Yu@Sun.COM 		 * In order to be compatible with SunOS 4.X we return
3918348SEric.Yu@Sun.COM 		 * EINVAL errors for bad lengths.
3928348SEric.Yu@Sun.COM 		 */
3938348SEric.Yu@Sun.COM 		if (!(optd->opdes_props & OP_VARLEN)) {
3948348SEric.Yu@Sun.COM 			/* fixed length - size must match */
3958348SEric.Yu@Sun.COM 			if (len != optd->opdes_size) {
3968348SEric.Yu@Sun.COM 				return (EINVAL);
3978348SEric.Yu@Sun.COM 			}
3988348SEric.Yu@Sun.COM 		}
3998348SEric.Yu@Sun.COM 	} else {
4008348SEric.Yu@Sun.COM 		if (check) {
4018348SEric.Yu@Sun.COM 			if (!OA_RWX_ANYPRIV(optd))
4028348SEric.Yu@Sun.COM 				/* any of "rwx" permission but not none */
4038348SEric.Yu@Sun.COM 				return (-TBADOPT);
4048348SEric.Yu@Sun.COM 		}
4058348SEric.Yu@Sun.COM 		/*
4068348SEric.Yu@Sun.COM 		 * XXX Since T_CURRENT was not there in TLI and the
4078348SEric.Yu@Sun.COM 		 * official TLI inspired TPI standard, getsockopt()
4088348SEric.Yu@Sun.COM 		 * API uses T_CHECK (for T_CURRENT semantics)
409*11042SErik.Nordmark@Sun.COM 		 * Thus T_CHECK includes the T_CURRENT semantics due to that
410*11042SErik.Nordmark@Sun.COM 		 * historical use.
4118348SEric.Yu@Sun.COM 		 */
4128348SEric.Yu@Sun.COM 		if (!OA_READ_PERMISSION(optd, cr)) {
4138348SEric.Yu@Sun.COM 			/* can't read option value */
4148348SEric.Yu@Sun.COM 			if (!(OA_MATCHED_PRIV(optd, cr)) &&
4158348SEric.Yu@Sun.COM 			    OA_R_ANYPRIV(optd)) {
4168348SEric.Yu@Sun.COM 				/*
4178348SEric.Yu@Sun.COM 				 * not privileged but privilege
4188348SEric.Yu@Sun.COM 				 * will help in reading option value.
4198348SEric.Yu@Sun.COM 				 */
4208348SEric.Yu@Sun.COM 				return (-TACCES);
4218348SEric.Yu@Sun.COM 			} else {
4228348SEric.Yu@Sun.COM 				return (-TBADOPT);
4238348SEric.Yu@Sun.COM 			}
4248348SEric.Yu@Sun.COM 		}
4258348SEric.Yu@Sun.COM 	}
4268348SEric.Yu@Sun.COM 	if (max_len != NULL)
4278348SEric.Yu@Sun.COM 		*max_len = optd->opdes_size;
4288348SEric.Yu@Sun.COM 
4298348SEric.Yu@Sun.COM 	/* We liked it.  Keep going. */
4308348SEric.Yu@Sun.COM 	return (0);
4318348SEric.Yu@Sun.COM }
432