xref: /illumos-gate/usr/src/uts/common/inet/proto_set.c (revision 0f1702c5201310f0529cd5abb77652e5e9b241b6)
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