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